Merge branch 'trunk' of github.com:rtfeldman/roc into repl_from_memory_trait

This commit is contained in:
Brian Carroll 2022-01-28 12:41:45 +00:00
commit 382ae948e1
67 changed files with 950 additions and 680 deletions

21
Cargo.lock generated
View file

@ -3254,6 +3254,7 @@ dependencies = [
"roc_parse", "roc_parse",
"roc_problem", "roc_problem",
"roc_region", "roc_region",
"roc_target",
"roc_types", "roc_types",
"roc_unify", "roc_unify",
"snafu", "snafu",
@ -3283,6 +3284,7 @@ dependencies = [
"roc_reporting", "roc_reporting",
"roc_solve", "roc_solve",
"roc_std", "roc_std",
"roc_target",
"roc_types", "roc_types",
"roc_unify", "roc_unify",
"serde_json", "serde_json",
@ -3297,6 +3299,7 @@ dependencies = [
"roc_collections", "roc_collections",
"roc_module", "roc_module",
"roc_region", "roc_region",
"roc_target",
"roc_types", "roc_types",
] ]
@ -3350,6 +3353,7 @@ dependencies = [
"roc_region", "roc_region",
"roc_reporting", "roc_reporting",
"roc_solve", "roc_solve",
"roc_target",
"roc_test_utils", "roc_test_utils",
"roc_types", "roc_types",
"roc_unify", "roc_unify",
@ -3416,6 +3420,7 @@ dependencies = [
"roc_module", "roc_module",
"roc_parse", "roc_parse",
"roc_region", "roc_region",
"roc_target",
"roc_types", "roc_types",
"snafu", "snafu",
"tempfile", "tempfile",
@ -3508,6 +3513,7 @@ dependencies = [
"roc_region", "roc_region",
"roc_solve", "roc_solve",
"roc_std", "roc_std",
"roc_target",
"roc_types", "roc_types",
"roc_unify", "roc_unify",
"target-lexicon", "target-lexicon",
@ -3526,6 +3532,7 @@ dependencies = [
"roc_module", "roc_module",
"roc_mono", "roc_mono",
"roc_std", "roc_std",
"roc_target",
"target-lexicon", "target-lexicon",
] ]
@ -3540,6 +3547,7 @@ dependencies = [
"roc_module", "roc_module",
"roc_mono", "roc_mono",
"roc_std", "roc_std",
"roc_target",
] ]
[[package]] [[package]]
@ -3587,6 +3595,7 @@ dependencies = [
"roc_region", "roc_region",
"roc_reporting", "roc_reporting",
"roc_solve", "roc_solve",
"roc_target",
"roc_types", "roc_types",
"roc_unify", "roc_unify",
"tempfile", "tempfile",
@ -3621,6 +3630,7 @@ dependencies = [
"roc_region", "roc_region",
"roc_solve", "roc_solve",
"roc_std", "roc_std",
"roc_target",
"roc_types", "roc_types",
"roc_unify", "roc_unify",
"static_assertions", "static_assertions",
@ -3680,6 +3690,7 @@ dependencies = [
"roc_problem", "roc_problem",
"roc_region", "roc_region",
"roc_solve", "roc_solve",
"roc_target",
"roc_test_utils", "roc_test_utils",
"roc_types", "roc_types",
"ven_pretty", "ven_pretty",
@ -3702,6 +3713,7 @@ dependencies = [
"roc_problem", "roc_problem",
"roc_region", "roc_region",
"roc_solve", "roc_solve",
"roc_target",
"roc_types", "roc_types",
"roc_unify", "roc_unify",
"tempfile", "tempfile",
@ -3717,6 +3729,13 @@ dependencies = [
"quickcheck_macros", "quickcheck_macros",
] ]
[[package]]
name = "roc_target"
version = "0.1.0"
dependencies = [
"target-lexicon",
]
[[package]] [[package]]
name = "roc_test_utils" name = "roc_test_utils"
version = "0.1.0" version = "0.1.0"
@ -4263,6 +4282,7 @@ dependencies = [
"roc_reporting", "roc_reporting",
"roc_solve", "roc_solve",
"roc_std", "roc_std",
"roc_target",
"roc_types", "roc_types",
"roc_unify", "roc_unify",
"target-lexicon", "target-lexicon",
@ -4284,6 +4304,7 @@ dependencies = [
"roc_load", "roc_load",
"roc_module", "roc_module",
"roc_mono", "roc_mono",
"roc_target",
"test_mono_macros", "test_mono_macros",
] ]

View file

@ -22,6 +22,7 @@ members = [
"compiler/build", "compiler/build",
"compiler/arena_pool", "compiler/arena_pool",
"compiler/test_gen", "compiler/test_gen",
"compiler/roc_target",
"vendor/ena", "vendor/ena",
"vendor/inkwell", "vendor/inkwell",
"vendor/pathfinding", "vendor/pathfinding",

View file

@ -17,6 +17,7 @@ roc_problem = { path = "../compiler/problem" }
roc_types = { path = "../compiler/types" } roc_types = { path = "../compiler/types" }
roc_unify = { path = "../compiler/unify"} roc_unify = { path = "../compiler/unify"}
roc_load = { path = "../compiler/load" } roc_load = { path = "../compiler/load" }
roc_target = { path = "../compiler/roc_target" }
roc_error_macros = { path = "../error_macros" } roc_error_macros = { path = "../error_macros" }
arrayvec = "0.7.2" arrayvec = "0.7.2"
bumpalo = { version = "3.8.0", features = ["collections"] } bumpalo = { version = "3.8.0", features = ["collections"] }

View file

@ -3,6 +3,7 @@ use std::path::Path;
use bumpalo::Bump; use bumpalo::Bump;
use roc_collections::all::MutMap; use roc_collections::all::MutMap;
use roc_load::file::LoadedModule; use roc_load::file::LoadedModule;
use roc_target::TargetInfo;
pub fn load_module(src_file: &Path) -> LoadedModule { pub fn load_module(src_file: &Path) -> LoadedModule {
let subs_by_module = MutMap::default(); let subs_by_module = MutMap::default();
@ -19,7 +20,7 @@ pub fn load_module(src_file: &Path) -> LoadedModule {
) )
}), }),
subs_by_module, subs_by_module,
8, TargetInfo::default_x86_64(),
roc_can::builtins::builtin_defs_map, roc_can::builtins::builtin_defs_map,
); );

View file

@ -61,6 +61,7 @@ roc_load = { path = "../compiler/load" }
roc_gen_llvm = { path = "../compiler/gen_llvm", optional = true } roc_gen_llvm = { path = "../compiler/gen_llvm", optional = true }
roc_build = { path = "../compiler/build", default-features = false } roc_build = { path = "../compiler/build", default-features = false }
roc_fmt = { path = "../compiler/fmt" } roc_fmt = { path = "../compiler/fmt" }
roc_target = { path = "../compiler/roc_target" }
roc_reporting = { path = "../reporting" } roc_reporting = { path = "../reporting" }
roc_error_macros = { path = "../error_macros" } roc_error_macros = { path = "../error_macros" }
roc_editor = { path = "../editor", optional = true } roc_editor = { path = "../editor", optional = true }

View file

@ -8,6 +8,7 @@ use roc_can::builtins::builtin_defs_map;
use roc_collections::all::MutMap; use roc_collections::all::MutMap;
use roc_load::file::LoadingProblem; use roc_load::file::LoadingProblem;
use roc_mono::ir::OptLevel; use roc_mono::ir::OptLevel;
use roc_target::TargetInfo;
use std::path::PathBuf; use std::path::PathBuf;
use std::time::{Duration, SystemTime}; use std::time::{Duration, SystemTime};
use target_lexicon::Triple; use target_lexicon::Triple;
@ -58,7 +59,7 @@ pub fn build_file<'a>(
target_valgrind: bool, target_valgrind: bool,
) -> Result<BuiltFile, LoadingProblem<'a>> { ) -> Result<BuiltFile, LoadingProblem<'a>> {
let compilation_start = SystemTime::now(); 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 // Step 1: compile the app and generate the .o file
let subs_by_module = MutMap::default(); let subs_by_module = MutMap::default();
@ -72,7 +73,7 @@ pub fn build_file<'a>(
stdlib, stdlib,
src_dir.as_path(), src_dir.as_path(),
subs_by_module, subs_by_module,
ptr_bytes, target_info,
builtin_defs_map, 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 // only used for generating errors. We don't do code generation, so hardcoding should be fine
// we need monomorphization for when exhaustiveness checking // 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 // Step 1: compile the app and generate the .o file
let subs_by_module = MutMap::default(); let subs_by_module = MutMap::default();
@ -370,7 +371,7 @@ pub fn check_file(
stdlib, stdlib,
src_dir.as_path(), src_dir.as_path(),
subs_by_module, subs_by_module,
ptr_bytes, target_info,
builtin_defs_map, builtin_defs_map,
)?; )?;

View file

@ -13,6 +13,7 @@ use roc_mono::layout::{
}; };
use roc_parse::ast::{AssignedField, Collection, Expr, StrLiteral}; use roc_parse::ast::{AssignedField, Collection, Expr, StrLiteral};
use roc_region::all::{Loc, Region}; use roc_region::all::{Loc, Region};
use roc_target::TargetInfo;
use roc_types::subs::{Content, FlatType, GetSubsSlice, RecordFields, Subs, UnionTags, Variable}; use roc_types::subs::{Content, FlatType, GetSubsSlice, RecordFields, Subs, UnionTags, Variable};
use std::cmp::{max_by_key, min_by_key}; use std::cmp::{max_by_key, min_by_key};
@ -21,8 +22,8 @@ use super::from_memory::AppMemory;
struct Env<'a, 'env, M> { struct Env<'a, 'env, M> {
arena: &'a Bump, arena: &'a Bump,
subs: &'env Subs, subs: &'env Subs,
ptr_bytes: u32,
app_memory: M, app_memory: M,
target_info: TargetInfo,
interns: &'env Interns, interns: &'env Interns,
home: ModuleId, home: ModuleId,
} }
@ -49,14 +50,14 @@ pub unsafe fn jit_to_ast<'a, M: AppMemory>(
interns: &'a Interns, interns: &'a Interns,
home: ModuleId, home: ModuleId,
subs: &'a Subs, subs: &'a Subs,
ptr_bytes: u32, target_info: TargetInfo,
app_memory: M, app_memory: M,
) -> Result<Expr<'a>, ToAstProblem> { ) -> Result<Expr<'a>, ToAstProblem> {
let env = Env { let env = Env {
arena, arena,
subs, subs,
ptr_bytes,
app_memory, app_memory,
target_info,
interns, interns,
home, home,
}; };
@ -176,7 +177,7 @@ fn get_tags_vars_and_variant<'a, M: AppMemory>(
let vars_of_tag: MutMap<_, _> = tags_vec.iter().cloned().collect(); let vars_of_tag: MutMap<_, _> = tags_vec.iter().cloned().collect();
let union_variant = 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) (vars_of_tag, union_variant)
} }
@ -210,7 +211,7 @@ fn tag_id_from_data<'a, M: AppMemory>(
data_addr: usize, data_addr: usize,
) -> i64 { ) -> i64 {
let offset = union_layout let offset = union_layout
.data_size_without_tag_id(env.ptr_bytes) .data_size_without_tag_id(env.target_info)
.unwrap(); .unwrap();
let tag_id_addr = data_addr + offset as usize; let tag_id_addr = data_addr + offset as usize;
@ -247,10 +248,10 @@ fn tag_id_from_recursive_ptr<'a, M: AppMemory>(
union_layout: UnionLayout, union_layout: UnionLayout,
rec_addr: usize, rec_addr: usize,
) -> (i64, usize) { ) -> (i64, usize) {
let tag_in_ptr = union_layout.stores_tag_id_in_pointer(env.ptr_bytes); let tag_in_ptr = union_layout.stores_tag_id_in_pointer(env.target_info);
if tag_in_ptr { if tag_in_ptr {
let masked_data_addr = deref_addr_of_addr(env, rec_addr); let masked_data_addr = deref_addr_of_addr(env, rec_addr);
let (tag_id_bits, tag_id_mask) = UnionLayout::tag_id_pointer_bits_and_mask(env.ptr_bytes); let (tag_id_bits, tag_id_mask) = UnionLayout::tag_id_pointer_bits_and_mask(env.target_info);
let tag_id = masked_data_addr & tag_id_mask; let tag_id = masked_data_addr & tag_id_mask;
// Clear the tag ID data from the pointer // Clear the tag ID data from the pointer
@ -397,7 +398,7 @@ fn jit_to_ast_help<'a, M: AppMemory>(
let fields = [Layout::u64(), *layout]; let fields = [Layout::u64(), *layout];
let layout = Layout::Struct(&fields); 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!( run_jit_function_dynamic_type!(
lib, lib,
@ -408,7 +409,7 @@ fn jit_to_ast_help<'a, M: AppMemory>(
) )
} }
Layout::Union(UnionLayout::NonRecursive(_)) => { 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!( Ok(run_jit_function_dynamic_type!(
lib, lib,
main_fn_name, main_fn_name,
@ -424,7 +425,7 @@ fn jit_to_ast_help<'a, M: AppMemory>(
| Layout::Union(UnionLayout::NonNullableUnwrapped(_)) | Layout::Union(UnionLayout::NonNullableUnwrapped(_))
| Layout::Union(UnionLayout::NullableUnwrapped { .. }) | Layout::Union(UnionLayout::NullableUnwrapped { .. })
| Layout::Union(UnionLayout::NullableWrapped { .. }) => { | 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!( Ok(run_jit_function_dynamic_type!(
lib, lib,
main_fn_name, main_fn_name,
@ -520,7 +521,7 @@ fn addr_to_ast<'a, M: AppMemory>(
} }
(_, Layout::Builtin(Builtin::List(elem_layout))) => { (_, Layout::Builtin(Builtin::List(elem_layout))) => {
let elem_addr = env.app_memory.deref_usize(addr); let elem_addr = env.app_memory.deref_usize(addr);
let len = env.app_memory.deref_usize(addr + env.ptr_bytes as usize); let len = env.app_memory.deref_usize(addr + env.target_info.ptr_width() as usize);
list_to_ast(env, elem_addr, len, elem_layout, content) list_to_ast(env, elem_addr, len, elem_layout, content)
} }
@ -761,7 +762,7 @@ fn list_to_ast<'a, M: AppMemory>(
let arena = env.arena; let arena = env.arena;
let mut output = Vec::with_capacity_in(len, 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 { for index in 0..len {
let offset_bytes = index * elem_size; let offset_bytes = index * elem_size;
@ -835,7 +836,7 @@ where
output.push(&*arena.alloc(loc_expr)); output.push(&*arena.alloc(loc_expr));
// Advance the field pointer to the next field. // Advance the field pointer to the next field.
field_addr += layout.stack_size(env.ptr_bytes) as usize; field_addr += layout.stack_size(env.target_info) as usize;
} }
output output
@ -919,7 +920,7 @@ fn struct_to_ast<'a, M: AppMemory>(
output.push(loc_field); output.push(loc_field);
// Advance the field pointer to the next field. // Advance the field pointer to the next field.
field_addr += field_layout.stack_size(env.ptr_bytes) as usize; field_addr += field_layout.stack_size(env.target_info) as usize;
} }
let output = output.into_bump_slice(); let output = output.into_bump_slice();
@ -1094,8 +1095,13 @@ fn byte_to_ast<'a, M: AppMemory>(env: &Env<'a, '_, M>, value: u8, content: &Cont
.map(|(a, b)| (a.clone(), b.to_vec())) .map(|(a, b)| (a.clone(), b.to_vec()))
.collect(); .collect();
let union_variant = let union_variant = union_sorted_tags_help(
union_sorted_tags_help(env.arena, tags_vec, None, env.subs, env.ptr_bytes); env.arena,
tags_vec,
None,
env.subs,
env.target_info,
);
match union_variant { match union_variant {
UnionVariant::ByteUnion(tagnames) => { UnionVariant::ByteUnion(tagnames) => {

View file

@ -14,6 +14,7 @@ use roc_load::file::LoadingProblem;
use roc_mono::ir::OptLevel; use roc_mono::ir::OptLevel;
use roc_parse::parser::SyntaxError; use roc_parse::parser::SyntaxError;
use roc_region::all::LineInfo; use roc_region::all::LineInfo;
use roc_target::TargetInfo;
use roc_types::pretty_print::{content_to_string, name_all_type_vars}; use roc_types::pretty_print::{content_to_string, name_all_type_vars};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::str::from_utf8_unchecked; use std::str::from_utf8_unchecked;
@ -44,7 +45,7 @@ pub fn gen_and_eval<'a>(
let module_src = promote_expr_to_module(src_str); 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 exposed_types = MutMap::default();
let loaded = roc_load::file::load_and_monomorphize_from_str( let loaded = roc_load::file::load_and_monomorphize_from_str(
@ -54,7 +55,7 @@ pub fn gen_and_eval<'a>(
&stdlib, &stdlib,
src_dir, src_dir,
exposed_types, exposed_types,
ptr_bytes, target_info,
builtin_defs_map, builtin_defs_map,
); );
@ -134,7 +135,6 @@ pub fn gen_and_eval<'a>(
} else { } else {
let context = Context::create(); let context = Context::create();
let builder = context.create_builder(); 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( let module = arena.alloc(roc_gen_llvm::llvm::build::module_from_builtins(
&target, &context, "", &target, &context, "",
)); ));
@ -182,7 +182,7 @@ pub fn gen_and_eval<'a>(
context: &context, context: &context,
interns, interns,
module, module,
ptr_bytes, target_info,
is_gen_test: true, // so roc_panic is generated is_gen_test: true, // so roc_panic is generated
// important! we don't want any procedures to get the C calling convention // important! we don't want any procedures to get the C calling convention
exposed_to_host: MutSet::default(), exposed_to_host: MutSet::default(),
@ -238,7 +238,7 @@ pub fn gen_and_eval<'a>(
&env.interns, &env.interns,
home, home,
&subs, &subs,
ptr_bytes, target_info,
AppMemoryInternal, AppMemoryInternal,
) )
}; };

View file

@ -376,11 +376,11 @@ mod cli_run {
// use_valgrind: true, // use_valgrind: true,
// }, // },
cli:"cli" => Example { cli:"cli" => Example {
filename: "Echo.roc", filename: "form.roc",
executable_filename: "echo", executable_filename: "form",
stdin: &["Giovanni\n", "Giorgio\n"], stdin: &["Giovanni\n", "Giorgio\n"],
input_file: None, input_file: None,
expected_ending: "Hi, Giovanni Giorgio!\n", expected_ending: "Hi, Giovanni Giorgio! 👋\n",
use_valgrind: true, use_valgrind: true,
}, },
tui:"tui" => Example { tui:"tui" => Example {
@ -421,9 +421,11 @@ mod cli_run {
macro_rules! benchmarks { macro_rules! benchmarks {
($($test_name:ident => $benchmark:expr,)+) => { ($($test_name:ident => $benchmark:expr,)+) => {
$( $(
#[test] #[test]
#[cfg_attr(not(debug_assertions), serial(benchmark))] #[cfg_attr(not(debug_assertions), serial(benchmark))]
#[cfg(all(not(feature = "wasm32-cli-run"), not(feature = "i386-cli-run")))]
fn $test_name() { fn $test_name() {
let benchmark = $benchmark; let benchmark = $benchmark;
let file_name = examples_dir("benchmarks").join(benchmark.filename); let file_name = examples_dir("benchmarks").join(benchmark.filename);

View file

@ -19,6 +19,7 @@ roc_unify = { path = "../unify" }
roc_solve = { path = "../solve" } roc_solve = { path = "../solve" }
roc_mono = { path = "../mono" } roc_mono = { path = "../mono" }
roc_load = { path = "../load" } roc_load = { path = "../load" }
roc_target = { path = "../roc_target" }
roc_gen_llvm = { path = "../gen_llvm", optional = true } roc_gen_llvm = { path = "../gen_llvm", optional = true }
roc_gen_wasm = { path = "../gen_wasm", optional = true } roc_gen_wasm = { path = "../gen_wasm", optional = true }
roc_gen_dev = { path = "../gen_dev", default-features = false } roc_gen_dev = { path = "../gen_dev", default-features = false }

View file

@ -235,7 +235,7 @@ pub fn gen_from_mono_module_llvm(
let code_gen_start = SystemTime::now(); let code_gen_start = SystemTime::now();
// Generate the binary // 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 context = Context::create();
let module = arena.alloc(module_from_builtins(target, &context, "app")); let module = arena.alloc(module_from_builtins(target, &context, "app"));
@ -286,7 +286,7 @@ pub fn gen_from_mono_module_llvm(
context: &context, context: &context,
interns: loaded.interns, interns: loaded.interns,
module, module,
ptr_bytes, target_info,
// in gen_tests, the compiler provides roc_panic // in gen_tests, the compiler provides roc_panic
// and sets up the setjump/longjump exception handling // and sets up the setjump/longjump exception handling
is_gen_test: false, is_gen_test: false,

View file

@ -10,3 +10,4 @@ roc_collections = { path = "../collections" }
roc_region = { path = "../region" } roc_region = { path = "../region" }
roc_module = { path = "../module" } roc_module = { path = "../module" }
roc_types = { path = "../types" } roc_types = { path = "../types" }
roc_target = { path = "../roc_target" }

View file

@ -1,4 +1,5 @@
use roc_module::symbol::Symbol; use roc_module::symbol::Symbol;
use roc_target::TargetInfo;
use std::ops::Index; use std::ops::Index;
pub const BUILTINS_HOST_OBJ_PATH: &str = env!( 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 std::mem::align_of;
use FloatWidth::*; use FloatWidth::*;
// TODO actually alignment is architecture-specific // TODO actually alignment is architecture-specific
match self { match self {
F32 => align_of::<f32>() as u32, 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, 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 std::mem::align_of;
use IntWidth::*; use IntWidth::*;
// TODO actually alignment is architecture-specific
match self { match self {
U8 | I8 => align_of::<i8>() as u32, U8 | I8 => align_of::<i8>() as u32,
U16 | I16 => align_of::<i16>() as u32, U16 | I16 => align_of::<i16>() as u32,
U32 | I32 => align_of::<i32>() 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, U128 | I128 => align_of::<i128>() as u32,
} }
} }

View file

@ -124,7 +124,11 @@ where
// This is a type alias // This is a type alias
// the symbol should already be added to the scope when this module is canonicalized // 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 // but now we know this symbol by a different identifier, so we still need to add it to
// the scope // the scope

View file

@ -16,6 +16,7 @@ roc_builtins = { path = "../builtins" }
roc_unify = { path = "../unify" } roc_unify = { path = "../unify" }
roc_solve = { path = "../solve" } roc_solve = { path = "../solve" }
roc_mono = { path = "../mono" } roc_mono = { path = "../mono" }
roc_target = { path = "../roc_target" }
roc_error_macros = { path = "../../error_macros" } roc_error_macros = { path = "../../error_macros" }
bumpalo = { version = "3.8.0", features = ["collections"] } bumpalo = { version = "3.8.0", features = ["collections"] }
target-lexicon = "0.12.2" target-lexicon = "0.12.2"

View file

@ -7,12 +7,13 @@ use roc_module::symbol::{Interns, Symbol};
use roc_mono::code_gen_help::CodeGenHelp; use roc_mono::code_gen_help::CodeGenHelp;
use roc_mono::ir::{BranchInfo, JoinPointId, Literal, Param, ProcLayout, SelfRecursive, Stmt}; use roc_mono::ir::{BranchInfo, JoinPointId, Literal, Param, ProcLayout, SelfRecursive, Stmt};
use roc_mono::layout::{Builtin, Layout}; use roc_mono::layout::{Builtin, Layout};
use roc_target::TargetInfo;
use std::marker::PhantomData; use std::marker::PhantomData;
pub mod aarch64; pub mod aarch64;
pub mod x86_64; pub mod x86_64;
const PTR_SIZE: u32 = 8; const TARGET_INFO: TargetInfo = TargetInfo::default_x86_64();
pub trait CallConv<GeneralReg: RegTrait, FloatReg: RegTrait> { pub trait CallConv<GeneralReg: RegTrait, FloatReg: RegTrait> {
const BASE_PTR_REG: GeneralReg; const BASE_PTR_REG: GeneralReg;
@ -308,7 +309,7 @@ pub fn new_backend_64bit<
phantom_cc: PhantomData, phantom_cc: PhantomData,
env, env,
interns, 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], helper_proc_symbols: bumpalo::vec![in env.arena],
proc_name: None, proc_name: None,
is_self_recursive: None, is_self_recursive: None,
@ -974,7 +975,7 @@ impl<
} }
fn create_struct(&mut self, sym: &Symbol, layout: &Layout<'a>, fields: &'a [Symbol]) { 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 let Layout::Struct(field_layouts) = layout {
if struct_size > 0 { if struct_size > 0 {
@ -991,7 +992,7 @@ impl<
let mut current_offset = offset; let mut current_offset = offset;
for (field, field_layout) in fields.iter().zip(field_layouts.iter()) { for (field, field_layout) in fields.iter().zip(field_layouts.iter()) {
self.copy_symbol_to_stack_offset(current_offset, field, field_layout); 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; current_offset += field_size as i32;
} }
} else { } else {
@ -1029,14 +1030,14 @@ impl<
if let Some(SymbolStorage::Base { offset, .. }) = self.symbol_storage_map.get(structure) { if let Some(SymbolStorage::Base { offset, .. }) = self.symbol_storage_map.get(structure) {
let mut data_offset = *offset; let mut data_offset = *offset;
for i in 0..index { 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; data_offset += field_size as i32;
} }
self.symbol_storage_map.insert( self.symbol_storage_map.insert(
*sym, *sym,
SymbolStorage::Base { SymbolStorage::Base {
offset: data_offset, 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, owned: false,
}, },
); );
@ -1569,10 +1570,10 @@ impl<
{ {
debug_assert_eq!( debug_assert_eq!(
*size, *size,
layout.stack_size(PTR_SIZE), layout.stack_size(TARGET_INFO),
"expected struct to have same size as data being stored in it" "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_reg64_base32(&mut self.buf, tmp_reg, from_offset + i);
ASM::mov_base32_reg64(&mut self.buf, to_offset + i, tmp_reg); ASM::mov_base32_reg64(&mut self.buf, to_offset + i, tmp_reg);
} }

View file

@ -1,4 +1,4 @@
use crate::generic64::{Assembler, CallConv, RegTrait, SymbolStorage, PTR_SIZE}; use crate::generic64::{Assembler, CallConv, RegTrait, SymbolStorage, TARGET_INFO};
use crate::{ use crate::{
single_register_builtins, single_register_floats, single_register_integers, Relocation, 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 { fn returns_via_arg_pointer(ret_layout: &Layout) -> bool {
// TODO: This may need to be more complex/extended to fully support the calling convention. // 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 // 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 { fn returns_via_arg_pointer(ret_layout: &Layout) -> bool {
// TODO: This is not fully correct there are some exceptions for "vector" types. // 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 // 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
} }
} }

View file

@ -12,6 +12,7 @@ roc_module = { path = "../module" }
roc_builtins = { path = "../builtins" } roc_builtins = { path = "../builtins" }
roc_error_macros = { path = "../../error_macros" } roc_error_macros = { path = "../../error_macros" }
roc_mono = { path = "../mono" } roc_mono = { path = "../mono" }
roc_target = { path = "../roc_target" }
roc_std = { path = "../../roc_std" } roc_std = { path = "../../roc_std" }
morphic_lib = { path = "../../vendor/morphic_lib" } morphic_lib = { path = "../../vendor/morphic_lib" }
bumpalo = { version = "3.8.0", features = ["collections"] } bumpalo = { version = "3.8.0", features = ["collections"] }

View file

@ -63,6 +63,7 @@ use roc_mono::ir::{
ModifyRc, OptLevel, ProcLayout, ModifyRc, OptLevel, ProcLayout,
}; };
use roc_mono::layout::{Builtin, LambdaSet, Layout, LayoutIds, TagIdIntType, UnionLayout}; use roc_mono::layout::{Builtin, LambdaSet, Layout, LayoutIds, TagIdIntType, UnionLayout};
use roc_target::TargetInfo;
use target_lexicon::{Architecture, OperatingSystem, Triple}; use target_lexicon::{Architecture, OperatingSystem, Triple};
/// This is for Inkwell's FunctionValue::verify - we want to know the verification /// This is for Inkwell's FunctionValue::verify - we want to know the verification
@ -166,7 +167,7 @@ pub struct Env<'a, 'ctx, 'env> {
pub compile_unit: &'env DICompileUnit<'ctx>, pub compile_unit: &'env DICompileUnit<'ctx>,
pub module: &'ctx Module<'ctx>, pub module: &'ctx Module<'ctx>,
pub interns: Interns, pub interns: Interns,
pub ptr_bytes: u32, pub target_info: TargetInfo,
pub is_gen_test: bool, pub is_gen_test: bool,
pub exposed_to_host: MutSet<Symbol>, 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> { pub fn ptr_int(&self) -> IntType<'ctx> {
let ctx = self.context; let ctx = self.context;
match self.ptr_bytes { match self.target_info.ptr_width() {
1 => ctx.i8_type(), roc_target::PtrWidth::Bytes4 => ctx.i32_type(),
2 => ctx.i16_type(), roc_target::PtrWidth::Bytes8 => ctx.i64_type(),
4 => ctx.i32_type(),
8 => ctx.i64_type(),
_ => panic!(
"Invalid target: Roc does't support compiling to {}-bit systems.",
self.ptr_bytes * 8
),
} }
} }
@ -212,11 +207,11 @@ impl<'a, 'ctx, 'env> Env<'a, 'ctx, 'env> {
/// on 64-bit systems, this is i128 /// on 64-bit systems, this is i128
/// on 32-bit systems, this is i64 /// on 32-bit systems, this is i64
pub fn str_list_c_abi(&self) -> IntType<'ctx> { 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 { pub fn small_str_bytes(&self) -> u32 {
self.ptr_bytes * 2 self.target_info.ptr_width() as u32 * 2
} }
pub fn build_intrinsic_call( 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> { 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); let alignment_iv = self.alignment_const(alignment);
alignment_iv.into() alignment_iv.into()
@ -317,12 +312,9 @@ impl<'a, 'ctx, 'env> Env<'a, 'ctx, 'env> {
) -> CallSiteValue<'ctx> { ) -> CallSiteValue<'ctx> {
let false_val = self.context.bool_type().const_int(0, false); let false_val = self.context.bool_type().const_int(0, false);
let intrinsic_name = match self.ptr_bytes { let intrinsic_name = match self.target_info.ptr_width() {
8 => LLVM_MEMSET_I64, roc_target::PtrWidth::Bytes8 => LLVM_MEMSET_I64,
4 => LLVM_MEMSET_I32, roc_target::PtrWidth::Bytes4 => LLVM_MEMSET_I32,
other => {
unreachable!("Unsupported number of ptr_bytes {:?}", other);
}
}; };
self.build_intrinsic_call( 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 raw_data_ptr = allocate_tag(env, parent, reuse_allocation, union_layout, tags);
let struct_type = env.context.struct_type(&field_types, false); 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 let tag_id_ptr = builder
.build_struct_gep(raw_data_ptr, TAG_ID_INDEX, "tag_id_index") .build_struct_gep(raw_data_ptr, TAG_ID_INDEX, "tag_id_index")
.unwrap(); .unwrap();
@ -1524,7 +1516,7 @@ pub fn build_tag<'a, 'ctx, 'env>(
UnionLayout::NonRecursive(tags) => { UnionLayout::NonRecursive(tags) => {
debug_assert!(union_size > 1); 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 tag_id_type = basic_type_from_layout(env, &tag_id_layout).into_int_type();
let wrapper_type = env let wrapper_type = env
@ -1711,7 +1703,7 @@ pub fn build_tag<'a, 'ctx, 'env>(
other_fields, other_fields,
} => { } => {
let tag_struct_type = 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 _ { if tag_id == *nullable_id as _ {
let output_type = tag_struct_type.ptr_type(AddressSpace::Generic); 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>, pointer: PointerValue<'ctx>,
) -> 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) // 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(); 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") .build_int_to_ptr(combined, pointer.get_type(), "to_ptr")
} }
pub fn tag_pointer_tag_id_bits_and_mask(ptr_bytes: u32) -> (u64, u64) { pub fn tag_pointer_tag_id_bits_and_mask(target_info: TargetInfo) -> (u64, u64) {
match ptr_bytes { match target_info.ptr_width() {
8 => (3, 0b0000_0111), roc_target::PtrWidth::Bytes8 => (3, 0b0000_0111),
4 => (2, 0b0000_0011), roc_target::PtrWidth::Bytes4 => (2, 0b0000_0011),
_ => unreachable!(),
} }
} }
@ -1813,7 +1804,7 @@ pub fn tag_pointer_read_tag_id<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>, env: &Env<'a, 'ctx, 'env>,
pointer: PointerValue<'ctx>, pointer: PointerValue<'ctx>,
) -> IntValue<'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 ptr_int = env.ptr_int();
let as_int = env.builder.build_ptr_to_int(pointer, ptr_int, "to_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> { ) -> PointerValue<'ctx> {
let ptr_int = env.ptr_int(); 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"); 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(_) => { UnionLayout::Recursive(_) => {
let argument_ptr = argument.into_pointer_value(); 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) get_tag_id_wrapped(env, argument_ptr)
} else { } else {
tag_pointer_read_tag_id(env, argument_ptr) 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); 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) get_tag_id_wrapped(env, argument_ptr)
} else { } else {
tag_pointer_read_tag_id(env, argument_ptr) 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 result = if field_layout.is_passed_by_reference() {
let field_type = basic_type_from_layout(env, &field_layout); 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"); let alloca = tag_alloca(env, field_type, "copied_tag");
if align_bytes > 0 { if align_bytes > 0 {
let size = env let size = env
.ptr_int() .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 env.builder
.build_memcpy(alloca, align_bytes, elem_ptr, align_bytes, size) .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>, env: &Env<'a, 'ctx, 'env>,
layout: &Layout<'a>, layout: &Layout<'a>,
) -> PointerValue<'ctx> { ) -> PointerValue<'ctx> {
let stack_size = layout.stack_size(env.ptr_bytes); let stack_size = layout.stack_size(env.target_info);
let alignment_bytes = layout.alignment_bytes(env.ptr_bytes); let alignment_bytes = layout.alignment_bytes(env.target_info);
let basic_type = basic_type_from_layout(env, layout); 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>, union_layout: UnionLayout<'a>,
fields: &[&[Layout<'a>]], fields: &[&[Layout<'a>]],
) -> PointerValue<'ctx> { ) -> 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 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()); 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 let mut stack_size = fields
.iter() .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() .max()
.unwrap_or_default(); .unwrap_or_default();
if union_layout.stores_tag_id_as_data(ptr_bytes) { 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 let alignment_bytes = fields
.iter() .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() .flatten()
.max() .max()
.unwrap_or(0); .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 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) 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 builder = env.builder;
let len_type = env.ptr_int(); 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 = { let ptr = {
// number of bytes we will allocated // number of bytes we will allocated
@ -2208,8 +2200,8 @@ pub fn allocate_with_refcount_help<'a, 'ctx, 'env>(
.into_pointer_value(); .into_pointer_value();
let index = match extra_bytes { let index = match extra_bytes {
n if n == env.ptr_bytes => 1, n if n == ptr_width_u32 => 1,
n if n == 2 * env.ptr_bytes => 2, n if n == 2 * ptr_width_u32 => 2,
_ => unreachable!("invalid extra_bytes, {}", extra_bytes), _ => 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 { 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 // the allocated pointer is the same as the refcounted pointer
unsafe { PointerToRefcount::from_ptr(env, ptr) } 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 // 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 // but in this case (because of alignment) not at the start of the allocated buffer
PointerToRefcount::from_ptr_to_data(env, data_ptr) 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 element_type.is_int_type() {
if false { if false {
let element_type = element_type.into_int_type(); 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 size = list_length * element_width as usize;
let alignment = element_layout let alignment = element_layout
.alignment_bytes(env.ptr_bytes) .alignment_bytes(env.target_info)
.max(env.ptr_bytes); .max(env.target_info.ptr_width() as u32);
let mut is_all_constant = true; 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 // runtime-evaluated elements
let mut runtime_evaluated_elements = Vec::with_capacity_in(list_length, env.arena); 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>, value: BasicValueEnum<'ctx>,
) { ) {
if layout.is_passed_by_reference() { 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 { if align_bytes > 0 {
let size = env let size = env
.ptr_int() .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 env.builder
.build_memcpy( .build_memcpy(
@ -2572,7 +2565,7 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>(
let destination = out_parameter.into_pointer_value(); let destination = out_parameter.into_pointer_value();
if layout.is_passed_by_reference() { 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 { if align_bytes > 0 {
let value_ptr = value.into_pointer_value(); let value_ptr = value.into_pointer_value();
@ -2585,7 +2578,7 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>(
} else { } else {
let size = env let size = env
.ptr_int() .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 env.builder
.build_memcpy( .build_memcpy(
@ -2776,21 +2769,21 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>(
match layout { match layout {
Layout::Builtin(Builtin::List(element_layout)) => { Layout::Builtin(Builtin::List(element_layout)) => {
debug_assert!(value.is_struct_value()); 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); build_list::decref(env, value.into_struct_value(), alignment);
} }
Layout::Builtin(Builtin::Dict(key_layout, value_layout)) => { Layout::Builtin(Builtin::Dict(key_layout, value_layout)) => {
debug_assert!(value.is_struct_value()); debug_assert!(value.is_struct_value());
let alignment = key_layout let alignment = key_layout
.alignment_bytes(env.ptr_bytes) .alignment_bytes(env.target_info)
.max(value_layout.alignment_bytes(env.ptr_bytes)); .max(value_layout.alignment_bytes(env.target_info));
build_dict::decref(env, value.into_struct_value(), alignment); build_dict::decref(env, value.into_struct_value(), alignment);
} }
Layout::Builtin(Builtin::Set(key_layout)) => { Layout::Builtin(Builtin::Set(key_layout)) => {
debug_assert!(value.is_struct_value()); 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); 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); 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) call_roc_function(env, roc_function, &wrapped_layout, arguments_for_call)
} else { } else {
call_roc_function(env, roc_function, &return_layout, arguments_for_call) call_roc_function(env, roc_function, &return_layout, arguments_for_call)
@ -3554,6 +3547,93 @@ fn expose_function_to_host_help_c_abi_gen_test<'a, 'ctx, 'env>(
c_function c_function
} }
fn expose_function_to_host_help_c_abi_v2<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
roc_function: FunctionValue<'ctx>,
arguments: &[Layout<'a>],
return_layout: Layout<'a>,
c_function_name: &str,
) -> FunctionValue<'ctx> {
let it = arguments.iter().map(|l| basic_type_from_layout(env, l));
let argument_types = Vec::from_iter_in(it, env.arena);
let return_type = basic_type_from_layout(env, &return_layout);
let cc_return = to_cc_return(env, &return_layout);
let roc_return = RocReturn::from_layout(env, &return_layout);
let c_function_type = cc_return.to_signature(env, return_type, argument_types.as_slice());
let c_function = add_func(
env.module,
c_function_name,
c_function_type,
Linkage::External,
C_CALL_CONV,
);
let subprogram = env.new_subprogram(c_function_name);
c_function.set_subprogram(subprogram);
// STEP 2: build the exposed function's body
let builder = env.builder;
let context = env.context;
let entry = context.append_basic_block(c_function, "entry");
builder.position_at_end(entry);
let params = c_function.get_params();
let param_types = Vec::from_iter_in(roc_function.get_type().get_param_types(), env.arena);
// drop the "return pointer" if it exists on the roc function
// and the c function does not return via pointer
let param_types = match (&roc_return, &cc_return) {
(RocReturn::ByPointer, CCReturn::Return) => &param_types[1..],
_ => &param_types,
};
debug_assert_eq!(params.len(), param_types.len());
let it = params.iter().zip(param_types).map(|(arg, fastcc_type)| {
let arg_type = arg.get_type();
if arg_type == *fastcc_type {
// the C and Fast calling conventions agree
*arg
} else {
complex_bitcast_check_size(env, *arg, *fastcc_type, "to_fastcc_type")
}
});
let arguments = Vec::from_iter_in(it, env.arena);
let value = call_roc_function(env, roc_function, &return_layout, arguments.as_slice());
match cc_return {
CCReturn::Return => match roc_return {
RocReturn::Return => {
env.builder.build_return(Some(&value));
}
RocReturn::ByPointer => {
let loaded = env
.builder
.build_load(value.into_pointer_value(), "load_result");
env.builder.build_return(Some(&loaded));
}
},
CCReturn::ByPointer => {
let out_ptr = c_function.get_nth_param(0).unwrap().into_pointer_value();
env.builder.build_store(out_ptr, value);
env.builder.build_return(None);
}
CCReturn::Void => {
env.builder.build_return(None);
}
}
c_function
}
fn expose_function_to_host_help_c_abi<'a, 'ctx, 'env>( fn expose_function_to_host_help_c_abi<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>, env: &Env<'a, 'ctx, 'env>,
ident_string: &str, ident_string: &str,
@ -3582,122 +3662,14 @@ fn expose_function_to_host_help_c_abi<'a, 'ctx, 'env>(
&format!("{}_generic", c_function_name), &format!("{}_generic", c_function_name),
); );
let wrapper_return_type = if env.is_gen_test { let c_function = expose_function_to_host_help_c_abi_v2(
roc_result_type(env, roc_function.get_type().get_return_type().unwrap()).into() env,
} else { roc_function,
// roc_function.get_type().get_return_type().unwrap() arguments,
basic_type_from_layout(env, &return_layout) return_layout,
};
let mut cc_argument_types = Vec::with_capacity_in(arguments.len(), env.arena);
for layout in arguments {
cc_argument_types.push(to_cc_type(env, layout));
}
// STEP 1: turn `f : a,b,c -> d` into `f : a,b,c, &d -> {}` if the C abi demands it
let mut argument_types = cc_argument_types;
let return_type = wrapper_return_type;
let cc_return = to_cc_return(env, &return_layout);
let c_function_type = match cc_return {
CCReturn::Void => env
.context
.void_type()
.fn_type(&function_arguments(env, &argument_types), false),
CCReturn::Return => return_type.fn_type(&function_arguments(env, &argument_types), false),
CCReturn::ByPointer => {
let output_type = return_type.ptr_type(AddressSpace::Generic);
argument_types.push(output_type.into());
env.context
.void_type()
.fn_type(&function_arguments(env, &argument_types), false)
}
};
let c_function = add_func(
env.module,
c_function_name, c_function_name,
c_function_type,
Linkage::External,
C_CALL_CONV,
); );
let subprogram = env.new_subprogram(c_function_name);
c_function.set_subprogram(subprogram);
// STEP 2: build the exposed function's body
let builder = env.builder;
let context = env.context;
let entry = context.append_basic_block(c_function, "entry");
builder.position_at_end(entry);
debug_info_init!(env, c_function);
// drop the final argument, which is the pointer we write the result into
let args_vector = c_function.get_params();
let mut args = args_vector.as_slice();
let args_length = args.len();
match cc_return {
CCReturn::Return => {
debug_assert_eq!(args.len(), roc_function.get_params().len());
}
CCReturn::Void => {
debug_assert_eq!(args.len(), roc_function.get_params().len());
}
CCReturn::ByPointer => match RocReturn::from_layout(env, &return_layout) {
RocReturn::ByPointer => {
debug_assert_eq!(args.len(), roc_function.get_params().len());
}
RocReturn::Return => {
args = &args[..args.len() - 1];
debug_assert_eq!(args.len(), roc_function.get_params().len());
}
},
}
let mut arguments_for_call = Vec::with_capacity_in(args.len(), env.arena);
let it = args.iter().zip(roc_function.get_type().get_param_types());
for (arg, fastcc_type) in it {
let arg_type = arg.get_type();
if arg_type == fastcc_type {
// the C and Fast calling conventions agree
arguments_for_call.push(*arg);
} else {
let cast = complex_bitcast_check_size(env, *arg, fastcc_type, "to_fastcc_type");
arguments_for_call.push(cast);
}
}
let arguments_for_call = arguments_for_call.into_bump_slice();
let call_result = call_roc_function(env, roc_function, &return_layout, arguments_for_call);
match cc_return {
CCReturn::Void => {
// TODO return empty struct here?
builder.build_return(None);
}
CCReturn::Return => {
builder.build_return(Some(&call_result));
}
CCReturn::ByPointer => {
let output_arg_index = args_length - 1;
let output_arg = c_function
.get_nth_param(output_arg_index as u32)
.unwrap()
.into_pointer_value();
builder.build_store(output_arg, call_result);
builder.build_return(None);
}
}
// STEP 3: build a {} -> u64 function that gives the size of the return type // STEP 3: build a {} -> u64 function that gives the size of the return type
let size_function_type = env.context.i64_type().fn_type(&[], false); let size_function_type = env.context.i64_type().fn_type(&[], false);
let size_function_name: String = format!("roc__{}_size", ident_string); let size_function_name: String = format!("roc__{}_size", ident_string);
@ -3713,20 +3685,30 @@ fn expose_function_to_host_help_c_abi<'a, 'ctx, 'env>(
let subprogram = env.new_subprogram(&size_function_name); let subprogram = env.new_subprogram(&size_function_name);
size_function.set_subprogram(subprogram); size_function.set_subprogram(subprogram);
let entry = context.append_basic_block(size_function, "entry"); let entry = env.context.append_basic_block(size_function, "entry");
builder.position_at_end(entry); env.builder.position_at_end(entry);
debug_info_init!(env, size_function); debug_info_init!(env, size_function);
let return_type = if env.is_gen_test {
roc_result_type(env, roc_function.get_type().get_return_type().unwrap()).into()
} else {
// roc_function.get_type().get_return_type().unwrap()
basic_type_from_layout(env, &return_layout)
};
let size: BasicValueEnum = return_type.size_of().unwrap().into(); let size: BasicValueEnum = return_type.size_of().unwrap().into();
builder.build_return(Some(&size)); env.builder.build_return(Some(&size));
c_function c_function
} }
pub fn get_sjlj_buffer<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>) -> PointerValue<'ctx> { 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") { let global = match env.module.get_global("roc_sjlj_buffer") {
Some(global) => global, Some(global) => global,
@ -3894,8 +3876,12 @@ fn make_exception_catcher<'a, 'ctx, 'env>(
function_value function_value
} }
fn roc_result_layout<'a>(arena: &'a Bump, return_layout: Layout<'a>, ptr_bytes: u32) -> Layout<'a> { fn roc_result_layout<'a>(
let elements = [Layout::u64(), Layout::usize(ptr_bytes), return_layout]; 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)) Layout::Struct(arena.alloc(elements))
} }
@ -4329,12 +4315,12 @@ pub fn build_closure_caller<'a, 'ctx, 'env>(
let call_result = call_roc_function(env, evaluator, return_layout, &evaluator_arguments); let call_result = call_roc_function(env, evaluator, return_layout, &evaluator_arguments);
if return_layout.is_passed_by_reference() { 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 { if align_bytes > 0 {
let size = env let size = env
.ptr_int() .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 env.builder
.build_memcpy( .build_memcpy(
@ -5020,7 +5006,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
Layout::Builtin(Builtin::List(element_layout)), Layout::Builtin(Builtin::List(element_layout)),
Layout::Builtin(Builtin::List(result_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( let roc_function_call = roc_function_call(
env, env,
@ -6075,8 +6061,8 @@ fn run_low_level<'a, 'ctx, 'env>(
{ {
bd.position_at_end(throw_block); bd.position_at_end(throw_block);
match env.ptr_bytes { match env.target_info.ptr_width() {
8 => { roc_target::PtrWidth::Bytes8 => {
let fn_ptr_type = context let fn_ptr_type = context
.void_type() .void_type()
.fn_type(&[], false) .fn_type(&[], false)
@ -6095,11 +6081,10 @@ fn run_low_level<'a, 'ctx, 'env>(
bd.build_unconditional_branch(then_block); bd.build_unconditional_branch(then_block);
} }
4 => { roc_target::PtrWidth::Bytes4 => {
// temporary WASM implementation // temporary WASM implementation
throw_exception(env, "An expectation failed!"); throw_exception(env, "An expectation failed!");
} }
_ => unreachable!(),
} }
} }
@ -6181,6 +6166,7 @@ impl RocReturn {
} }
} }
#[derive(Debug)]
enum CCReturn { enum CCReturn {
/// Return as normal /// Return as normal
Return, Return,
@ -6192,10 +6178,40 @@ enum CCReturn {
Void, Void,
} }
impl CCReturn {
fn to_signature<'a, 'ctx, 'env>(
&self,
env: &Env<'a, 'ctx, 'env>,
return_type: BasicTypeEnum<'ctx>,
argument_types: &[BasicTypeEnum<'ctx>],
) -> FunctionType<'ctx> {
match self {
CCReturn::ByPointer => {
// turn the output type into a pointer type. Make it the first argument to the function
let output_type = return_type.ptr_type(AddressSpace::Generic);
let mut arguments: Vec<'_, BasicTypeEnum> =
bumpalo::vec![in env.arena; output_type.into()];
arguments.extend(argument_types);
let arguments = function_arguments(env, &arguments);
env.context.void_type().fn_type(&arguments, false)
}
CCReturn::Return => {
let arguments = function_arguments(env, argument_types);
return_type.fn_type(&arguments, false)
}
CCReturn::Void => {
let arguments = function_arguments(env, argument_types);
env.context.void_type().fn_type(&arguments, false)
}
}
}
}
/// According to the C ABI, how should we return a value with the given layout? /// 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 { 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 return_size = layout.stack_size(env.target_info);
let pass_result_by_pointer = return_size > 2 * env.ptr_bytes; let pass_result_by_pointer = return_size > 2 * env.target_info.ptr_width() as u32;
if return_size == 0 { if return_size == 0 {
CCReturn::Void CCReturn::Void
@ -6268,22 +6284,7 @@ fn build_foreign_symbol<'a, 'ctx, 'env>(
arguments.push(value); arguments.push(value);
} }
let cc_type = match cc_return { let cc_type = cc_return.to_signature(env, return_type, cc_argument_types.as_slice());
CCReturn::Void => env
.context
.void_type()
.fn_type(&function_arguments(env, &cc_argument_types), false),
CCReturn::ByPointer => {
cc_argument_types.insert(0, return_type.ptr_type(AddressSpace::Generic).into());
env.context
.void_type()
.fn_type(&function_arguments(env, &cc_argument_types), false)
}
CCReturn::Return => {
return_type.fn_type(&function_arguments(env, &cc_argument_types), false)
}
};
let cc_function = get_foreign_symbol(env, foreign.clone(), cc_type); let cc_function = get_foreign_symbol(env, foreign.clone(), cc_type);
let fastcc_type = match roc_return { let fastcc_type = match roc_return {
@ -6323,7 +6324,6 @@ fn build_foreign_symbol<'a, 'ctx, 'env>(
if let CCReturn::ByPointer = cc_return { if let CCReturn::ByPointer = cc_return {
cc_arguments.push(return_pointer.into()); cc_arguments.push(return_pointer.into());
cc_argument_types.remove(0);
} }
let it = fastcc_parameters.into_iter().zip(cc_argument_types.iter()); let it = fastcc_parameters.into_iter().zip(cc_argument_types.iter());
@ -7129,7 +7129,9 @@ fn define_global_str_literal_ptr<'a, 'ctx, 'env>(
let ptr = unsafe { let ptr = unsafe {
env.builder.build_in_bounds_gep( env.builder.build_in_bounds_gep(
ptr, 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", "get_rc_ptr",
) )
}; };
@ -7159,11 +7161,11 @@ fn define_global_str_literal<'a, 'ctx, 'env>(
Some(current) => current, Some(current) => current,
None => { 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); let mut bytes = Vec::with_capacity_in(size, env.arena);
// insert NULL bytes for the refcount // 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()); bytes.push(env.context.i8_type().const_zero());
} }
@ -7182,7 +7184,7 @@ fn define_global_str_literal<'a, 'ctx, 'env>(
// strings are NULL-terminated, which means we can't store the refcount (which is 8 // strings are NULL-terminated, which means we can't store the refcount (which is 8
// NULL bytes) // NULL bytes)
global.set_constant(true); 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_unnamed_addr(true);
global.set_linkage(inkwell::module::Linkage::Private); global.set_linkage(inkwell::module::Linkage::Private);

View file

@ -17,14 +17,15 @@ use inkwell::AddressSpace;
use roc_builtins::bitcode; use roc_builtins::bitcode;
use roc_module::symbol::Symbol; use roc_module::symbol::Symbol;
use roc_mono::layout::{Builtin, Layout, LayoutIds}; use roc_mono::layout::{Builtin, Layout, LayoutIds};
use roc_target::TargetInfo;
#[repr(transparent)] #[repr(transparent)]
struct Alignment(u8); struct Alignment(u8);
impl Alignment { impl Alignment {
fn from_key_value_layout(key: &Layout, value: &Layout, ptr_bytes: u32) -> Alignment { fn from_key_value_layout(key: &Layout, value: &Layout, target_info: TargetInfo) -> Alignment {
let key_align = key.alignment_bytes(ptr_bytes); let key_align = key.alignment_bytes(target_info);
let value_align = value.alignment_bytes(ptr_bytes); let value_align = value.alignment_bytes(target_info);
let mut bits = key_align.max(value_align) as u8; 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 let key_width = env
.ptr_int() .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 let value_width = env
.ptr_int() .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 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 alignment_iv = alignment.as_int_value(env.context);
let hash_fn = build_hash_wrapper(env, layout_ids, key_layout); 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 let key_width = env
.ptr_int() .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 let value_width = env
.ptr_int() .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 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 alignment_iv = alignment.as_int_value(env.context);
let hash_fn = build_hash_wrapper(env, layout_ids, key_layout); 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 let key_width = env
.ptr_int() .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 let value_width = env
.ptr_int() .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 alignment_iv = alignment.as_int_value(env.context);
let hash_fn = build_hash_wrapper(env, layout_ids, key_layout); 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 let key_width = env
.ptr_int() .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 let value_width = env
.ptr_int() .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 alignment_iv = alignment.as_int_value(env.context);
let hash_fn = build_hash_wrapper(env, layout_ids, key_layout); 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 let key_width = env
.ptr_int() .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 let value_width = env
.ptr_int() .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 alignment_iv = alignment.as_int_value(env.context);
let (key_fn, value_fn) = match rc_operation { let (key_fn, value_fn) = match rc_operation {
@ -412,13 +413,13 @@ pub fn dict_keys<'a, 'ctx, 'env>(
let key_width = env let key_width = env
.ptr_int() .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 let value_width = env
.ptr_int() .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 alignment_iv = alignment.as_int_value(env.context);
let inc_key_fn = build_inc_wrapper(env, layout_ids, key_layout); 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>, env: &Env<'a, 'ctx, 'env>,
dict: BasicValueEnum<'ctx>, dict: BasicValueEnum<'ctx>,
) -> BasicValueEnum<'ctx> { ) -> BasicValueEnum<'ctx> {
match env.ptr_bytes { match env.target_info.ptr_width() {
4 => { roc_target::PtrWidth::Bytes4 => {
let target_type = env.context.custom_width_int_type(96).into(); let target_type = env.context.custom_width_int_type(96).into();
complex_bitcast(env.builder, dict, target_type, "to_i96") 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"); let dict_ptr = env.builder.build_alloca(zig_dict_type(env), "dict_ptr");
env.builder.build_store(dict_ptr, dict); env.builder.build_store(dict_ptr, dict);
dict_ptr.into() dict_ptr.into()
} }
_ => unreachable!(),
} }
} }
@ -483,13 +483,13 @@ pub fn dict_union<'a, 'ctx, 'env>(
let key_width = env let key_width = env
.ptr_int() .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 let value_width = env
.ptr_int() .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 alignment_iv = alignment.as_int_value(env.context);
let hash_fn = build_hash_wrapper(env, layout_ids, key_layout); 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 let key_width = env
.ptr_int() .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 let value_width = env
.ptr_int() .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 alignment_iv = alignment.as_int_value(env.context);
let hash_fn = build_hash_wrapper(env, layout_ids, key_layout); 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"); let accum_ptr = builder.build_alloca(accum_bt, "accum_ptr");
env.builder.build_store(accum_ptr, accum); 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 alignment_iv = alignment.as_int_value(env.context);
let output_ptr = builder.build_alloca(accum_bt, "output_ptr"); 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 let key_width = env
.ptr_int() .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 let value_width = env
.ptr_int() .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 alignment_iv = alignment.as_int_value(env.context);
let inc_value_fn = build_inc_wrapper(env, layout_ids, value_layout); 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 let key_width = env
.ptr_int() .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 value_width = env.ptr_int().const_zero();
let result_alloca = builder.build_alloca(zig_dict_type(env), "result_alloca"); let result_alloca = builder.build_alloca(zig_dict_type(env), "result_alloca");
let alignment = 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 alignment_iv = alignment.as_int_value(env.context);
let hash_fn = build_hash_wrapper(env, layout_ids, key_layout); let hash_fn = build_hash_wrapper(env, layout_ids, key_layout);

View file

@ -120,7 +120,7 @@ fn hash_builtin<'a, 'ctx, 'env>(
builtin: &Builtin<'a>, builtin: &Builtin<'a>,
when_recursive: WhenRecursive<'a>, when_recursive: WhenRecursive<'a>,
) -> IntValue<'ctx> { ) -> IntValue<'ctx> {
let ptr_bytes = env.ptr_bytes; let ptr_bytes = env.target_info;
match builtin { match builtin {
Builtin::Int(_) | Builtin::Float(_) | Builtin::Bool | Builtin::Decimal => { Builtin::Int(_) | Builtin::Float(_) | Builtin::Bool | Builtin::Decimal => {
@ -246,7 +246,7 @@ fn hash_struct<'a, 'ctx, 'env>(
when_recursive: WhenRecursive<'a>, when_recursive: WhenRecursive<'a>,
field_layouts: &[Layout<'a>], field_layouts: &[Layout<'a>],
) -> IntValue<'ctx> { ) -> IntValue<'ctx> {
let ptr_bytes = env.ptr_bytes; let ptr_bytes = env.target_info;
let layout = Layout::Struct(field_layouts); let layout = Layout::Struct(field_layouts);
@ -423,7 +423,7 @@ fn hash_tag<'a, 'ctx, 'env>(
env, env,
seed, seed,
hash_bytes, hash_bytes,
tag_id_layout.stack_size(env.ptr_bytes), tag_id_layout.stack_size(env.target_info),
); );
// hash the tag data // hash the tag data
@ -474,7 +474,7 @@ fn hash_tag<'a, 'ctx, 'env>(
env, env,
seed, seed,
hash_bytes, hash_bytes,
tag_id_layout.stack_size(env.ptr_bytes), tag_id_layout.stack_size(env.target_info),
); );
// hash the tag data // hash the tag data
@ -574,7 +574,7 @@ fn hash_tag<'a, 'ctx, 'env>(
env, env,
seed, seed,
hash_bytes, hash_bytes,
tag_id_layout.stack_size(env.ptr_bytes), tag_id_layout.stack_size(env.target_info),
); );
// hash tag data // hash tag data

View file

@ -87,7 +87,7 @@ pub fn layout_width<'a, 'ctx, 'env>(
layout: &Layout<'a>, layout: &Layout<'a>,
) -> BasicValueEnum<'ctx> { ) -> BasicValueEnum<'ctx> {
env.ptr_int() 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() .into()
} }
@ -1254,17 +1254,17 @@ pub fn allocate_list<'a, 'ctx, 'env>(
let ctx = env.context; let ctx = env.context;
let len_type = env.ptr_int(); 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 bytes_per_element = len_type.const_int(elem_bytes, false);
let number_of_data_bytes = let number_of_data_bytes =
builder.build_int_mul(bytes_per_element, number_of_elements, "data_length"); builder.build_int_mul(bytes_per_element, number_of_elements, "data_length");
// the refcount of a new list is initially 1 // the refcount of a new list is initially 1
// we assume that the list is indeed used (dead variables are eliminated) // 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 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) allocate_with_refcount_help(env, basic_type, alignment_bytes, number_of_data_bytes, rc1)
} }

View file

@ -10,6 +10,7 @@ use morphic_lib::UpdateMode;
use roc_builtins::bitcode::{self, IntWidth}; use roc_builtins::bitcode::{self, IntWidth};
use roc_module::symbol::Symbol; use roc_module::symbol::Symbol;
use roc_mono::layout::{Builtin, Layout}; use roc_mono::layout::{Builtin, Layout};
use roc_target::PtrWidth;
use super::build::load_symbol; use super::build::load_symbol;
@ -79,10 +80,9 @@ fn str_symbol_to_c_abi<'a, 'ctx, 'env>(
) -> IntValue<'ctx> { ) -> IntValue<'ctx> {
let string = load_symbol(scope, &symbol); let string = load_symbol(scope, &symbol);
let target_type = match env.ptr_bytes { let target_type = match env.target_info.ptr_width() {
8 => env.context.i128_type().into(), PtrWidth::Bytes8 => env.context.i128_type().into(),
4 => env.context.i64_type().into(), PtrWidth::Bytes4 => env.context.i64_type().into(),
_ => unreachable!(),
}; };
complex_bitcast(env.builder, string, target_type, "str_to_c_abi").into_int_value() 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); env.builder.build_store(cell, value);
let target_type = match env.ptr_bytes { let target_type = match env.target_info.ptr_width() {
8 => env.context.i128_type(), PtrWidth::Bytes8 => env.context.i128_type(),
4 => env.context.i64_type(), PtrWidth::Bytes4 => env.context.i64_type(),
_ => unreachable!(),
}; };
let target_type_ptr = env let target_type_ptr = env
@ -310,20 +309,19 @@ fn decode_from_utf8_result<'a, 'ctx, 'env>(
let builder = env.builder; let builder = env.builder;
let ctx = env.context; let ctx = env.context;
let fields = match env.ptr_bytes { let fields = match env.target_info.ptr_width() {
8 | 4 => [ PtrWidth::Bytes4 | PtrWidth::Bytes8 => [
env.ptr_int().into(), env.ptr_int().into(),
super::convert::zig_str_type(env).into(), super::convert::zig_str_type(env).into(),
env.context.bool_type().into(), env.context.bool_type().into(),
ctx.i8_type().into(), ctx.i8_type().into(),
], ],
_ => unreachable!(),
}; };
let record_type = env.context.struct_type(&fields, false); let record_type = env.context.struct_type(&fields, false);
match env.ptr_bytes { match env.target_info.ptr_width() {
8 | 4 => { PtrWidth::Bytes4 | PtrWidth::Bytes8 => {
let result_ptr_cast = env let result_ptr_cast = env
.builder .builder
.build_bitcast( .build_bitcast(
@ -337,7 +335,6 @@ fn decode_from_utf8_result<'a, 'ctx, 'env>(
.build_load(result_ptr_cast, "load_utf8_validate_bytes_result") .build_load(result_ptr_cast, "load_utf8_validate_bytes_result")
.into_struct_value() .into_struct_value()
} }
_ => unreachable!(),
} }
} }

View file

@ -4,6 +4,7 @@ use inkwell::types::{BasicType, BasicTypeEnum, FloatType, IntType, StructType};
use inkwell::AddressSpace; use inkwell::AddressSpace;
use roc_builtins::bitcode::{FloatWidth, IntWidth}; use roc_builtins::bitcode::{FloatWidth, IntWidth};
use roc_mono::layout::{Builtin, Layout, UnionLayout}; use roc_mono::layout::{Builtin, Layout, UnionLayout};
use roc_target::TargetInfo;
fn basic_type_from_record<'a, 'ctx, 'env>( fn basic_type_from_record<'a, 'ctx, 'env>(
env: &crate::llvm::build::Env<'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 { match union_layout {
NonRecursive(tags) => { 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() env.context.struct_type(&[data, tag_id_type], false).into()
} }
@ -44,9 +45,9 @@ pub fn basic_type_from_layout<'a, 'ctx, 'env>(
| NullableWrapped { | NullableWrapped {
other_tags: tags, .. 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 env.context
.struct_type(&[data, tag_id_type], false) .struct_type(&[data, tag_id_type], false)
.ptr_type(AddressSpace::Generic) .ptr_type(AddressSpace::Generic)
@ -56,11 +57,12 @@ pub fn basic_type_from_layout<'a, 'ctx, 'env>(
} }
} }
NullableUnwrapped { other_fields, .. } => { 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() block.ptr_type(AddressSpace::Generic).into()
} }
NonNullableUnwrapped(fields) => { 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() block.ptr_type(AddressSpace::Generic).into()
} }
} }
@ -95,7 +97,7 @@ pub fn basic_type_from_layout_1<'a, 'ctx, 'env>(
match union_layout { match union_layout {
NonRecursive(tags) => { 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); let struct_type = env.context.struct_type(&[data, tag_id_type], false);
struct_type.ptr_type(AddressSpace::Generic).into() struct_type.ptr_type(AddressSpace::Generic).into()
@ -104,9 +106,9 @@ pub fn basic_type_from_layout_1<'a, 'ctx, 'env>(
| NullableWrapped { | NullableWrapped {
other_tags: tags, .. 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 env.context
.struct_type(&[data, tag_id_type], false) .struct_type(&[data, tag_id_type], false)
.ptr_type(AddressSpace::Generic) .ptr_type(AddressSpace::Generic)
@ -116,11 +118,12 @@ pub fn basic_type_from_layout_1<'a, 'ctx, 'env>(
} }
} }
NullableUnwrapped { other_fields, .. } => { 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() block.ptr_type(AddressSpace::Generic).into()
} }
NonNullableUnwrapped(fields) => { 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() 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>( pub fn block_of_memory_slices<'ctx>(
context: &'ctx Context, context: &'ctx Context,
layouts: &[&[Layout<'_>]], layouts: &[&[Layout<'_>]],
ptr_bytes: u32, target_info: TargetInfo,
) -> BasicTypeEnum<'ctx> { ) -> BasicTypeEnum<'ctx> {
let mut union_size = 0; let mut union_size = 0;
for tag in layouts { for tag in layouts {
let mut total = 0; let mut total = 0;
for layout in tag.iter() { 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); union_size = union_size.max(total);
@ -206,13 +209,13 @@ pub fn block_of_memory_slices<'ctx>(
pub fn block_of_memory<'ctx>( pub fn block_of_memory<'ctx>(
context: &'ctx Context, context: &'ctx Context,
layout: &Layout<'_>, layout: &Layout<'_>,
ptr_bytes: u32, target_info: TargetInfo,
) -> BasicTypeEnum<'ctx> { ) -> BasicTypeEnum<'ctx> {
// TODO make this dynamic // 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 { 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) 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 /// The int type that the C ABI turns our RocList/RocStr into
pub fn str_list_int(ctx: &Context, ptr_bytes: u32) -> IntType<'_> { pub fn str_list_int(ctx: &Context, target_info: TargetInfo) -> IntType<'_> {
match ptr_bytes { match target_info.ptr_width() {
1 => ctx.i16_type(), roc_target::PtrWidth::Bytes4 => ctx.i64_type(),
2 => ctx.i32_type(), roc_target::PtrWidth::Bytes8 => ctx.i128_type(),
4 => ctx.i64_type(),
8 => ctx.i128_type(),
_ => panic!(
"Invalid target: Roc does't support compiling to {}-bit systems.",
ptr_bytes * 8
),
} }
} }

View file

@ -175,7 +175,9 @@ pub fn add_sjlj_roc_panic(env: &Env<'_, '_, '_>) {
let buffer = crate::llvm::build::get_sjlj_buffer(env); let buffer = crate::llvm::build::get_sjlj_buffer(env);
// write our error message pointer // 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 = let message_buffer_raw =
unsafe { builder.build_gep(buffer, &[index], "raw_msg_buffer_ptr") }; unsafe { builder.build_gep(buffer, &[index], "raw_msg_buffer_ptr") };
let message_buffer = builder.build_bitcast( let message_buffer = builder.build_bitcast(

View file

@ -18,21 +18,16 @@ use inkwell::{AddressSpace, IntPredicate};
use roc_module::symbol::Interns; use roc_module::symbol::Interns;
use roc_module::symbol::Symbol; use roc_module::symbol::Symbol;
use roc_mono::layout::{Builtin, Layout, LayoutIds, UnionLayout}; use roc_mono::layout::{Builtin, Layout, LayoutIds, UnionLayout};
use roc_target::TargetInfo;
/// "Infinite" reference count, for static values /// "Infinite" reference count, for static values
/// Ref counts are encoded as negative numbers where isize::MIN represents 1 /// Ref counts are encoded as negative numbers where isize::MIN represents 1
pub const REFCOUNT_MAX: usize = 0_usize; pub const REFCOUNT_MAX: usize = 0_usize;
pub fn refcount_1(ctx: &Context, ptr_bytes: u32) -> IntValue<'_> { pub fn refcount_1(ctx: &Context, target_info: TargetInfo) -> IntValue<'_> {
match ptr_bytes { match target_info.ptr_width() {
1 => ctx.i8_type().const_int(i8::MIN as u64, false), roc_target::PtrWidth::Bytes4 => ctx.i32_type().const_int(i32::MIN as u64, false),
2 => ctx.i16_type().const_int(i16::MIN as u64, false), roc_target::PtrWidth::Bytes8 => ctx.i64_type().const_int(i64::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
),
} }
} }
@ -98,7 +93,7 @@ impl<'ctx> PointerToRefcount<'ctx> {
pub fn is_1<'a, 'env>(&self, env: &Env<'a, 'ctx, 'env>) -> IntValue<'ctx> { pub fn is_1<'a, 'env>(&self, env: &Env<'a, 'ctx, 'env>) -> IntValue<'ctx> {
let current = self.get_refcount(env); 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 env.builder
.build_int_compare(IntPredicate::EQ, current, one, "is_one") .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>) { pub fn decrement<'a, 'env>(&self, env: &Env<'a, 'ctx, 'env>, layout: &Layout<'a>) {
let alignment = layout let alignment = layout
.allocation_alignment_bytes(env.ptr_bytes) .allocation_alignment_bytes(env.target_info)
.max(env.ptr_bytes); .max(env.target_info.ptr_width() as u32);
let context = env.context; let context = env.context;
let block = env.builder.get_insert_block().expect("to be in a function"); 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()); debug_assert!(arg_val.is_pointer_value());
let current_tag_id = get_tag_id(env, fn_val, &union_layout, arg_val); 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()) tag_pointer_clear_tag_id(env, arg_val.into_pointer_value())
} else { } else {
arg_val.into_pointer_value() arg_val.into_pointer_value()

View file

@ -11,5 +11,6 @@ roc_builtins = { path = "../builtins" }
roc_collections = { path = "../collections" } roc_collections = { path = "../collections" }
roc_module = { path = "../module" } roc_module = { path = "../module" }
roc_mono = { path = "../mono" } roc_mono = { path = "../mono" }
roc_target = { path = "../roc_target" }
roc_std = { path = "../../roc_std" } roc_std = { path = "../../roc_std" }
roc_error_macros = { path = "../../error_macros" } roc_error_macros = { path = "../../error_macros" }

View file

@ -26,7 +26,7 @@ use crate::wasm_module::{
}; };
use crate::{ use crate::{
copy_memory, round_up_to_alignment, CopyMemoryConfig, Env, DEBUG_LOG_SETTINGS, MEMORY_NAME, 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. /// 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) { for field in field_layouts.iter().take(index as usize) {
offset += field.stack_size(PTR_SIZE); offset += field.stack_size(TARGET_INFO);
} }
self.storage self.storage
.copy_value_from_memory(&mut self.code_builder, sym, local_id, offset); .copy_value_from_memory(&mut self.code_builder, sym, local_id, offset);
@ -1010,11 +1010,11 @@ impl<'a> WasmBackend<'a> {
elems: &'a [ListLiteralElement<'a>], elems: &'a [ListLiteralElement<'a>],
) { ) {
if let StoredValue::StackMemory { location, .. } = storage { 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 // Allocate heap space and store its address in a local variable
let heap_local_id = self.storage.create_anonymous_local(PTR_TYPE); 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.allocate_with_refcount(Some(size), heap_alignment, 1);
self.code_builder.set_local(heap_local_id); self.code_builder.set_local(heap_local_id);
@ -1099,9 +1099,9 @@ impl<'a> WasmBackend<'a> {
return; return;
} }
let stores_tag_id_as_data = union_layout.stores_tag_id_as_data(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(PTR_SIZE); 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(PTR_SIZE); 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 // We're going to use the pointer many times, so put it in a local variable
let stored_with_local = let stored_with_local =
@ -1138,7 +1138,7 @@ impl<'a> WasmBackend<'a> {
if stores_tag_id_as_data { if stores_tag_id_as_data {
let id_offset = data_offset + data_size - data_alignment; 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); let id_align = Align::from(id_align);
self.code_builder.get_local(local_id); 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) { if union_layout.stores_tag_id_as_data(TARGET_INFO) {
let (data_size, data_alignment) = union_layout.data_size_and_alignment(PTR_SIZE); let (data_size, data_alignment) = union_layout.data_size_and_alignment(TARGET_INFO);
let id_offset = data_size - data_alignment; 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); let id_align = Align::from(id_align);
self.storage self.storage
@ -1237,7 +1237,7 @@ impl<'a> WasmBackend<'a> {
Builtin::Int(IntWidth::U64) => self.code_builder.i64_load(id_align, id_offset), Builtin::Int(IntWidth::U64) => self.code_builder.i64_load(id_align, id_offset),
x => internal_error!("Unexpected layout for tag union id {:?}", x), 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 self.storage
.load_symbols(&mut self.code_builder, &[structure]); .load_symbols(&mut self.code_builder, &[structure]);
self.code_builder.i32_const(3); self.code_builder.i32_const(3);
@ -1284,7 +1284,7 @@ impl<'a> WasmBackend<'a> {
let field_offset: u32 = field_layouts let field_offset: u32 = field_layouts
.iter() .iter()
.take(index as usize) .take(index as usize)
.map(|field_layout| field_layout.stack_size(PTR_SIZE)) .map(|field_layout| field_layout.stack_size(TARGET_INFO))
.sum(); .sum();
// Get pointer and offset to the tag's data // 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 from_ptr = if stores_tag_id_in_pointer {
let ptr = self.storage.create_anonymous_local(ValueType::I32); let ptr = self.storage.create_anonymous_local(ValueType::I32);

View file

@ -2,7 +2,7 @@ use roc_builtins::bitcode::{FloatWidth, IntWidth};
use roc_mono::layout::{Layout, UnionLayout}; use roc_mono::layout::{Layout, UnionLayout};
use crate::wasm_module::ValueType; 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 /// Manually keep up to date with the Zig version we are using for builtins
pub const BUILTINS_ZIG_VERSION: ZigVersion = ZigVersion::Zig8; pub const BUILTINS_ZIG_VERSION: ZigVersion = ZigVersion::Zig8;
@ -47,8 +47,8 @@ impl WasmLayout {
use UnionLayout::*; use UnionLayout::*;
use ValueType::*; use ValueType::*;
let size = layout.stack_size(PTR_SIZE); let size = layout.stack_size(TARGET_INFO);
let alignment_bytes = layout.alignment_bytes(PTR_SIZE); let alignment_bytes = layout.alignment_bytes(TARGET_INFO);
match layout { match layout {
Layout::Builtin(Int(int_width)) => { Layout::Builtin(Int(int_width)) => {

View file

@ -6,20 +6,29 @@ pub mod wasm_module;
use bumpalo::{self, collections::Vec, Bump}; use bumpalo::{self, collections::Vec, Bump};
use roc_builtins::bitcode::IntWidth;
use roc_collections::all::{MutMap, MutSet}; use roc_collections::all::{MutMap, MutSet};
use roc_module::low_level::LowLevelWrapperType; use roc_module::low_level::LowLevelWrapperType;
use roc_module::symbol::{Interns, ModuleId, Symbol}; use roc_module::symbol::{Interns, ModuleId, Symbol};
use roc_mono::code_gen_help::CodeGenHelp; use roc_mono::code_gen_help::CodeGenHelp;
use roc_mono::ir::{Proc, ProcLayout}; use roc_mono::ir::{Proc, ProcLayout};
use roc_mono::layout::LayoutIds; use roc_mono::layout::LayoutIds;
use roc_target::TargetInfo;
use crate::backend::WasmBackend; use crate::backend::WasmBackend;
use crate::wasm_module::{ use crate::wasm_module::{
Align, CodeBuilder, Export, ExportType, LocalId, SymInfo, ValueType, WasmModule, 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; const PTR_TYPE: ValueType = ValueType::I32;
pub const STACK_POINTER_GLOBAL_ID: u32 = 0; pub const STACK_POINTER_GLOBAL_ID: u32 = 0;
@ -111,7 +120,7 @@ pub fn build_module_without_test_wrapper<'a>(
proc_symbols, proc_symbols,
initial_module, initial_module,
fn_index_offset, 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 { if DEBUG_LOG_SETTINGS.user_procs_ir {

View file

@ -18,6 +18,7 @@ roc_unify = { path = "../unify" }
roc_parse = { path = "../parse" } roc_parse = { path = "../parse" }
roc_solve = { path = "../solve" } roc_solve = { path = "../solve" }
roc_mono = { path = "../mono" } roc_mono = { path = "../mono" }
roc_target = { path = "../roc_target" }
roc_reporting = { path = "../../reporting" } roc_reporting = { path = "../../reporting" }
morphic_lib = { path = "../../vendor/morphic_lib" } morphic_lib = { path = "../../vendor/morphic_lib" }
ven_pretty = { path = "../../vendor/pretty" } ven_pretty = { path = "../../vendor/pretty" }

View file

@ -32,6 +32,7 @@ use roc_parse::parser::{FileError, Parser, SyntaxError};
use roc_region::all::{LineInfo, Loc, Region}; use roc_region::all::{LineInfo, Loc, Region};
use roc_solve::module::SolvedModule; use roc_solve::module::SolvedModule;
use roc_solve::solve; use roc_solve::solve;
use roc_target::TargetInfo;
use roc_types::solved_types::Solved; use roc_types::solved_types::Solved;
use roc_types::subs::{Subs, VarStore, Variable}; use roc_types::subs::{Subs, VarStore, Variable};
use roc_types::types::{Alias, Type}; use roc_types::types::{Alias, Type};
@ -878,7 +879,7 @@ struct State<'a> {
pub exposed_types: SubsByModule, pub exposed_types: SubsByModule,
pub output_path: Option<&'a str>, pub output_path: Option<&'a str>,
pub platform_path: PlatformPath<'a>, pub platform_path: PlatformPath<'a>,
pub ptr_bytes: u32, pub target_info: TargetInfo,
pub module_cache: ModuleCache<'a>, pub module_cache: ModuleCache<'a>,
pub dependencies: Dependencies<'a>, pub dependencies: Dependencies<'a>,
@ -1083,7 +1084,7 @@ pub fn load_and_typecheck<'a, F>(
stdlib: &'a StdLib, stdlib: &'a StdLib,
src_dir: &Path, src_dir: &Path,
exposed_types: SubsByModule, exposed_types: SubsByModule,
ptr_bytes: u32, target_info: TargetInfo,
look_up_builtin: F, look_up_builtin: F,
) -> Result<LoadedModule, LoadingProblem<'a>> ) -> Result<LoadedModule, LoadingProblem<'a>>
where where
@ -1100,7 +1101,7 @@ where
src_dir, src_dir,
exposed_types, exposed_types,
Phase::SolveTypes, Phase::SolveTypes,
ptr_bytes, target_info,
look_up_builtin, look_up_builtin,
)? { )? {
Monomorphized(_) => unreachable!(""), Monomorphized(_) => unreachable!(""),
@ -1115,7 +1116,7 @@ pub fn load_and_monomorphize<'a, F>(
stdlib: &'a StdLib, stdlib: &'a StdLib,
src_dir: &Path, src_dir: &Path,
exposed_types: SubsByModule, exposed_types: SubsByModule,
ptr_bytes: u32, target_info: TargetInfo,
look_up_builtin: F, look_up_builtin: F,
) -> Result<MonomorphizedModule<'a>, LoadingProblem<'a>> ) -> Result<MonomorphizedModule<'a>, LoadingProblem<'a>>
where where
@ -1132,7 +1133,7 @@ where
src_dir, src_dir,
exposed_types, exposed_types,
Phase::MakeSpecializations, Phase::MakeSpecializations,
ptr_bytes, target_info,
look_up_builtin, look_up_builtin,
)? { )? {
Monomorphized(module) => Ok(module), Monomorphized(module) => Ok(module),
@ -1148,7 +1149,7 @@ pub fn load_and_monomorphize_from_str<'a, F>(
stdlib: &'a StdLib, stdlib: &'a StdLib,
src_dir: &Path, src_dir: &Path,
exposed_types: SubsByModule, exposed_types: SubsByModule,
ptr_bytes: u32, target_info: TargetInfo,
look_up_builtin: F, look_up_builtin: F,
) -> Result<MonomorphizedModule<'a>, LoadingProblem<'a>> ) -> Result<MonomorphizedModule<'a>, LoadingProblem<'a>>
where where
@ -1165,7 +1166,7 @@ where
src_dir, src_dir,
exposed_types, exposed_types,
Phase::MakeSpecializations, Phase::MakeSpecializations,
ptr_bytes, target_info,
look_up_builtin, look_up_builtin,
)? { )? {
Monomorphized(module) => Ok(module), Monomorphized(module) => Ok(module),
@ -1317,7 +1318,7 @@ fn load<'a, F>(
src_dir: &Path, src_dir: &Path,
exposed_types: SubsByModule, exposed_types: SubsByModule,
goal_phase: Phase, goal_phase: Phase,
ptr_bytes: u32, target_info: TargetInfo,
look_up_builtins: F, look_up_builtins: F,
) -> Result<LoadResult<'a>, LoadingProblem<'a>> ) -> Result<LoadResult<'a>, LoadingProblem<'a>>
where where
@ -1433,7 +1434,7 @@ where
worker_arena, worker_arena,
src_dir, src_dir,
msg_tx.clone(), msg_tx.clone(),
ptr_bytes, target_info,
look_up_builtins, look_up_builtins,
); );
@ -1474,7 +1475,7 @@ where
let mut state = State { let mut state = State {
root_id, root_id,
ptr_bytes, target_info,
platform_data: None, platform_data: None,
goal_phase, goal_phase,
stdlib, stdlib,
@ -1999,7 +2000,7 @@ fn update<'a>(
let layout_cache = state let layout_cache = state
.layout_caches .layout_caches
.pop() .pop()
.unwrap_or_else(|| LayoutCache::new(state.ptr_bytes)); .unwrap_or_else(|| LayoutCache::new(state.target_info));
let typechecked = TypeCheckedModule { let typechecked = TypeCheckedModule {
module_id, module_id,
@ -3812,7 +3813,7 @@ fn make_specializations<'a>(
mut layout_cache: LayoutCache<'a>, mut layout_cache: LayoutCache<'a>,
specializations_we_must_make: Vec<ExternalSpecializations>, specializations_we_must_make: Vec<ExternalSpecializations>,
mut module_timing: ModuleTiming, mut module_timing: ModuleTiming,
ptr_bytes: u32, target_info: TargetInfo,
) -> Msg<'a> { ) -> Msg<'a> {
let make_specializations_start = SystemTime::now(); let make_specializations_start = SystemTime::now();
let mut mono_problems = Vec::new(); let mut mono_problems = Vec::new();
@ -3824,7 +3825,7 @@ fn make_specializations<'a>(
subs: &mut subs, subs: &mut subs,
home, home,
ident_ids: &mut ident_ids, ident_ids: &mut ident_ids,
ptr_bytes, target_info,
update_mode_ids: &mut update_mode_ids, update_mode_ids: &mut update_mode_ids,
// call_specialization_counter=0 is reserved // call_specialization_counter=0 is reserved
call_specialization_counter: 1, call_specialization_counter: 1,
@ -3895,7 +3896,7 @@ fn build_pending_specializations<'a>(
decls: Vec<Declaration>, decls: Vec<Declaration>,
mut module_timing: ModuleTiming, mut module_timing: ModuleTiming,
mut layout_cache: LayoutCache<'a>, mut layout_cache: LayoutCache<'a>,
ptr_bytes: u32, target_info: TargetInfo,
// TODO remove // TODO remove
exposed_to_host: ExposedToHost, exposed_to_host: ExposedToHost,
) -> Msg<'a> { ) -> Msg<'a> {
@ -3920,7 +3921,7 @@ fn build_pending_specializations<'a>(
subs: &mut subs, subs: &mut subs,
home, home,
ident_ids: &mut ident_ids, ident_ids: &mut ident_ids,
ptr_bytes, target_info,
update_mode_ids: &mut update_mode_ids, update_mode_ids: &mut update_mode_ids,
// call_specialization_counter=0 is reserved // call_specialization_counter=0 is reserved
call_specialization_counter: 1, call_specialization_counter: 1,
@ -4128,7 +4129,7 @@ fn run_task<'a, F>(
arena: &'a Bump, arena: &'a Bump,
src_dir: &Path, src_dir: &Path,
msg_tx: MsgSender<'a>, msg_tx: MsgSender<'a>,
ptr_bytes: u32, target_info: TargetInfo,
look_up_builtins: F, look_up_builtins: F,
) -> Result<(), LoadingProblem<'a>> ) -> Result<(), LoadingProblem<'a>>
where where
@ -4206,7 +4207,7 @@ where
decls, decls,
module_timing, module_timing,
layout_cache, layout_cache,
ptr_bytes, target_info,
exposed_to_host, exposed_to_host,
)), )),
MakeSpecializations { MakeSpecializations {
@ -4226,7 +4227,7 @@ where
layout_cache, layout_cache,
specializations_we_must_make, specializations_we_must_make,
module_timing, module_timing,
ptr_bytes, target_info,
)), )),
}?; }?;

View file

@ -28,6 +28,8 @@ mod test_load {
use roc_types::subs::Subs; use roc_types::subs::Subs;
use std::collections::HashMap; use std::collections::HashMap;
const TARGET_INFO: roc_target::TargetInfo = roc_target::TargetInfo::default_x86_64();
// HELPERS // HELPERS
fn multiple_modules(files: Vec<(&str, &str)>) -> Result<LoadedModule, String> { fn multiple_modules(files: Vec<(&str, &str)>) -> Result<LoadedModule, String> {
@ -110,7 +112,7 @@ mod test_load {
arena.alloc(stdlib), arena.alloc(stdlib),
dir.path(), dir.path(),
exposed_types, exposed_types,
8, TARGET_INFO,
builtin_defs_map, builtin_defs_map,
) )
}; };
@ -134,7 +136,7 @@ mod test_load {
arena.alloc(roc_builtins::std::standard_stdlib()), arena.alloc(roc_builtins::std::standard_stdlib()),
src_dir.as_path(), src_dir.as_path(),
subs_by_module, subs_by_module,
8, TARGET_INFO,
builtin_defs_map, builtin_defs_map,
); );
let mut loaded_module = match loaded { let mut loaded_module = match loaded {
@ -305,7 +307,7 @@ mod test_load {
arena.alloc(roc_builtins::std::standard_stdlib()), arena.alloc(roc_builtins::std::standard_stdlib()),
src_dir.as_path(), src_dir.as_path(),
subs_by_module, subs_by_module,
8, TARGET_INFO,
builtin_defs_map, builtin_defs_map,
); );

View file

@ -16,6 +16,7 @@ roc_solve = { path = "../solve" }
roc_std = { path = "../../roc_std" } roc_std = { path = "../../roc_std" }
roc_problem = { path = "../problem" } roc_problem = { path = "../problem" }
roc_builtins = { path = "../builtins" } roc_builtins = { path = "../builtins" }
roc_target = { path = "../roc_target" }
ven_pretty = { path = "../../vendor/pretty" } ven_pretty = { path = "../../vendor/pretty" }
morphic_lib = { path = "../../vendor/morphic_lib" } morphic_lib = { path = "../../vendor/morphic_lib" }
bumpalo = { version = "3.8.0", features = ["collections"] } bumpalo = { version = "3.8.0", features = ["collections"] }

View file

@ -590,7 +590,9 @@ fn eq_list<'a>(
// let size = literal int // let size = literal int
let size = root.create_symbol(ident_ids, "size"); 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 size_stmt = |next| Stmt::Let(size, size_expr, layout_isize, next);
// let list_size = len_1 * size // let list_size = len_1 * size

View file

@ -1,9 +1,9 @@
use bumpalo::collections::vec::Vec; use bumpalo::collections::vec::Vec;
use bumpalo::Bump; use bumpalo::Bump;
use roc_builtins::bitcode::IntWidth;
use roc_module::ident::Ident; use roc_module::ident::Ident;
use roc_module::low_level::LowLevel; use roc_module::low_level::LowLevel;
use roc_module::symbol::{IdentIds, ModuleId, Symbol}; use roc_module::symbol::{IdentIds, ModuleId, Symbol};
use roc_target::TargetInfo;
use crate::ir::{ use crate::ir::{
Call, CallSpecId, CallType, Expr, HostExposedLayouts, JoinPointId, ModifyRc, Proc, ProcLayout, Call, CallSpecId, CallType, Expr, HostExposedLayouts, JoinPointId, ModifyRc, Proc, ProcLayout,
@ -74,19 +74,19 @@ pub struct Context<'a> {
pub struct CodeGenHelp<'a> { pub struct CodeGenHelp<'a> {
arena: &'a Bump, arena: &'a Bump,
home: ModuleId, home: ModuleId,
ptr_size: u32, target_info: TargetInfo,
layout_isize: Layout<'a>, layout_isize: Layout<'a>,
specializations: Vec<'a, Specialization<'a>>, specializations: Vec<'a, Specialization<'a>>,
debug_recursion_depth: usize, debug_recursion_depth: usize,
} }
impl<'a> CodeGenHelp<'a> { 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 { CodeGenHelp {
arena, arena,
home, home,
ptr_size: intwidth_isize.stack_size(), target_info,
layout_isize: Layout::Builtin(Builtin::Int(intwidth_isize)), layout_isize: Layout::usize(target_info),
specializations: Vec::with_capacity_in(16, arena), specializations: Vec::with_capacity_in(16, arena),
debug_recursion_depth: 0, debug_recursion_depth: 0,
} }

View file

@ -207,7 +207,7 @@ pub fn rc_ptr_from_data_ptr<'a>(
// Mask for lower bits (for tag union id) // Mask for lower bits (for tag union id)
let mask_sym = root.create_symbol(ident_ids, "mask"); 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 mask_stmt = |next| Stmt::Let(mask_sym, mask_expr, root.layout_isize, next);
let masked_sym = root.create_symbol(ident_ids, "masked"); let masked_sym = root.create_symbol(ident_ids, "masked");
@ -222,7 +222,7 @@ pub fn rc_ptr_from_data_ptr<'a>(
// Pointer size constant // Pointer size constant
let ptr_size_sym = root.create_symbol(ident_ids, "ptr_size"); 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); let ptr_size_stmt = |next| Stmt::Let(ptr_size_sym, ptr_size_expr, root.layout_isize, next);
// Refcount address // Refcount address
@ -382,7 +382,7 @@ fn refcount_str<'a>(
// A pointer to the refcount value itself // A pointer to the refcount value itself
let rc_ptr = root.create_symbol(ident_ids, "rc_ptr"); 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 ret_unit_stmt = rc_return_stmt(root, ident_ids, ctx);
let mod_rc_stmt = modify_refcount( 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 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 ret_stmt = rc_return_stmt(root, ident_ids, ctx);
let modify_list = modify_refcount( let modify_list = modify_refcount(
@ -584,7 +584,9 @@ fn refcount_list_elems<'a>(
// let size = literal int // let size = literal int
let elem_size = root.create_symbol(ident_ids, "elem_size"); 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 elem_size_stmt = |next| Stmt::Let(elem_size, elem_size_expr, layout_isize, next);
// let list_size = len * size // let list_size = len * size
@ -972,7 +974,7 @@ fn refcount_union_rec<'a>(
let rc_structure_stmt = { let rc_structure_stmt = {
let rc_ptr = root.create_symbol(ident_ids, "rc_ptr"); 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 ret_stmt = rc_return_stmt(root, ident_ids, ctx);
let modify_structure_stmt = modify_refcount( let modify_structure_stmt = modify_refcount(
root, root,
@ -988,7 +990,7 @@ fn refcount_union_rec<'a>(
ident_ids, ident_ids,
structure, structure,
rc_ptr, 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), 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( let modify_structure_stmt = modify_refcount(
root, root,
ident_ids, ident_ids,
@ -1095,7 +1097,7 @@ fn refcount_union_tailrec<'a>(
ident_ids, ident_ids,
current, current,
rc_ptr, 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), root.arena.alloc(modify_structure_stmt),
) )
}; };

View file

@ -16,6 +16,7 @@ use roc_module::symbol::{IdentIds, ModuleId, Symbol};
use roc_problem::can::RuntimeError; use roc_problem::can::RuntimeError;
use roc_region::all::{Loc, Region}; use roc_region::all::{Loc, Region};
use roc_std::RocDec; use roc_std::RocDec;
use roc_target::TargetInfo;
use roc_types::subs::{Content, FlatType, StorageSubs, Subs, Variable, VariableSubsSlice}; use roc_types::subs::{Content, FlatType, StorageSubs, Subs, Variable, VariableSubsSlice};
use std::collections::HashMap; use std::collections::HashMap;
use ven_pretty::{BoxAllocator, DocAllocator, DocBuilder}; use ven_pretty::{BoxAllocator, DocAllocator, DocBuilder};
@ -1071,7 +1072,7 @@ pub struct Env<'a, 'i> {
pub problems: &'i mut std::vec::Vec<MonoProblem>, pub problems: &'i mut std::vec::Vec<MonoProblem>,
pub home: ModuleId, pub home: ModuleId,
pub ident_ids: &'i mut IdentIds, pub ident_ids: &'i mut IdentIds,
pub ptr_bytes: u32, pub target_info: TargetInfo,
pub update_mode_ids: &'i mut UpdateModeIds, pub update_mode_ids: &'i mut UpdateModeIds,
pub call_specialization_counter: u32, pub call_specialization_counter: u32,
} }
@ -2471,7 +2472,7 @@ fn specialize_external<'a>(
env.arena, env.arena,
); );
let ptr_bytes = env.ptr_bytes; let ptr_bytes = env.target_info;
combined.sort_by(|(_, layout1), (_, layout2)| { combined.sort_by(|(_, layout1), (_, layout2)| {
let size1 = layout1.alignment_bytes(ptr_bytes); let size1 = layout1.alignment_bytes(ptr_bytes);
@ -2504,7 +2505,7 @@ fn specialize_external<'a>(
env.arena, env.arena,
); );
let ptr_bytes = env.ptr_bytes; let ptr_bytes = env.target_info;
combined.sort_by(|(_, layout1), (_, layout2)| { combined.sort_by(|(_, layout1), (_, layout2)| {
let size1 = layout1.alignment_bytes(ptr_bytes); let size1 = layout1.alignment_bytes(ptr_bytes);
@ -3009,14 +3010,14 @@ fn try_make_literal<'a>(
match can_expr { match can_expr {
Int(_, precision, _, int) => { 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)), IntOrFloat::Int(_) => Some(Literal::Int(*int)),
_ => unreachable!("unexpected float precision for integer"), _ => unreachable!("unexpected float precision for integer"),
} }
} }
Float(_, precision, float_str, float) => { 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::Float(_) => Some(Literal::Float(*float)),
IntOrFloat::DecimalFloatType => { IntOrFloat::DecimalFloatType => {
let dec = match RocDec::from_str(float_str) { 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))), // Str(string) => Some(Literal::Str(env.arena.alloc(string))),
Num(var, num_str, num) => { Num(var, num_str, num) => {
// first figure out what kind of number this is // 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::Int(_) => Some(Literal::Int((*num).into())),
IntOrFloat::Float(_) => Some(Literal::Float(*num as f64)), IntOrFloat::Float(_) => Some(Literal::Float(*num as f64)),
IntOrFloat::DecimalFloatType => { IntOrFloat::DecimalFloatType => {
@ -3072,7 +3073,7 @@ pub fn with_hole<'a>(
match can_expr { match can_expr {
Int(_, precision, _, int) => { 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( IntOrFloat::Int(precision) => Stmt::Let(
assigned, assigned,
Expr::Literal(Literal::Int(int)), Expr::Literal(Literal::Int(int)),
@ -3084,7 +3085,7 @@ pub fn with_hole<'a>(
} }
Float(_, precision, float_str, float) => { 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( IntOrFloat::Float(precision) => Stmt::Let(
assigned, assigned,
Expr::Literal(Literal::Float(float)), Expr::Literal(Literal::Float(float)),
@ -3116,7 +3117,7 @@ pub fn with_hole<'a>(
Num(var, num_str, num) => { Num(var, num_str, num) => {
// first figure out what kind of number this is // 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( IntOrFloat::Int(precision) => Stmt::Let(
assigned, assigned,
Expr::Literal(Literal::Int(num.into())), Expr::Literal(Literal::Int(num.into())),
@ -3393,7 +3394,7 @@ pub fn with_hole<'a>(
env.arena, env.arena,
record_var, record_var,
env.subs, env.subs,
env.ptr_bytes, env.target_info,
) { ) {
Ok(fields) => fields, Ok(fields) => fields,
Err(_) => return Stmt::RuntimeError("Can't create record with improper layout"), Err(_) => return Stmt::RuntimeError("Can't create record with improper layout"),
@ -3754,7 +3755,7 @@ pub fn with_hole<'a>(
env.arena, env.arena,
record_var, record_var,
env.subs, env.subs,
env.ptr_bytes, env.target_info,
) { ) {
Ok(fields) => fields, Ok(fields) => fields,
Err(_) => return Stmt::RuntimeError("Can't access record with improper layout"), Err(_) => return Stmt::RuntimeError("Can't access record with improper layout"),
@ -3911,7 +3912,7 @@ pub fn with_hole<'a>(
env.arena, env.arena,
record_var, record_var,
env.subs, env.subs,
env.ptr_bytes, env.target_info,
) { ) {
Ok(fields) => fields, Ok(fields) => fields,
Err(_) => return Stmt::RuntimeError("Can't update record with improper layout"), Err(_) => return Stmt::RuntimeError("Can't update record with improper layout"),
@ -4586,7 +4587,7 @@ fn construct_closure_data<'a>(
env.arena, env.arena,
); );
let ptr_bytes = env.ptr_bytes; let ptr_bytes = env.target_info;
combined.sort_by(|(_, layout1), (_, layout2)| { combined.sort_by(|(_, layout1), (_, layout2)| {
let size1 = layout1.alignment_bytes(ptr_bytes); let size1 = layout1.alignment_bytes(ptr_bytes);
@ -4617,7 +4618,7 @@ fn construct_closure_data<'a>(
env.arena, env.arena,
); );
let ptr_bytes = env.ptr_bytes; let ptr_bytes = env.target_info;
combined.sort_by(|(_, layout1), (_, layout2)| { combined.sort_by(|(_, layout1), (_, layout2)| {
let size1 = layout1.alignment_bytes(ptr_bytes); let size1 = layout1.alignment_bytes(ptr_bytes);
@ -4692,7 +4693,7 @@ fn convert_tag_union<'a>(
) -> Stmt<'a> { ) -> Stmt<'a> {
use crate::layout::UnionVariant::*; use crate::layout::UnionVariant::*;
let res_variant = 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 { let variant = match res_variant {
Ok(cached) => cached, Ok(cached) => cached,
Err(LayoutProblem::UnresolvedTypeVar(_)) => { 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); let symbol = possible_reuse_symbol(env, procs, &arg.value);
field_symbols_temp.push((alignment, symbol, ((var, arg), &*env.arena.alloc(symbol)))); 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) { let captured_symbols = match *env.subs.get_content_without_compacting(function_type) {
Content::Structure(FlatType::Func(_, closure_var, _)) => { 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) => { Ok(lambda_set) => {
if let Layout::Struct(&[]) = lambda_set.runtime_representation() { if let Layout::Struct(&[]) = lambda_set.runtime_representation() {
CapturedSymbols::None CapturedSymbols::None
@ -7621,7 +7622,7 @@ fn from_can_pattern_help<'a>(
Underscore => Ok(Pattern::Underscore), Underscore => Ok(Pattern::Underscore),
Identifier(symbol) => Ok(Pattern::Identifier(*symbol)), Identifier(symbol) => Ok(Pattern::Identifier(*symbol)),
IntLiteral(var, _, int) => { 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)), IntOrFloat::Int(precision) => Ok(Pattern::IntLiteral(*int as i128, precision)),
other => { other => {
panic!( panic!(
@ -7633,7 +7634,7 @@ fn from_can_pattern_help<'a>(
} }
FloatLiteral(var, float_str, float) => { FloatLiteral(var, float_str, float) => {
// TODO: Can I reuse num_argument_to_int_or_float here if I pass in true? // 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(_) => { IntOrFloat::Int(_) => {
panic!("Invalid precision for float pattern {:?}", var) panic!("Invalid precision for float pattern {:?}", var)
} }
@ -7663,7 +7664,7 @@ fn from_can_pattern_help<'a>(
Err(RuntimeError::UnsupportedPattern(*region)) Err(RuntimeError::UnsupportedPattern(*region))
} }
NumLiteral(var, num_str, num) => { 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::Int(precision) => Ok(Pattern::IntLiteral(*num as i128, precision)),
IntOrFloat::Float(precision) => Ok(Pattern::FloatLiteral(*num as u64, precision)), IntOrFloat::Float(precision) => Ok(Pattern::FloatLiteral(*num as u64, precision)),
IntOrFloat::DecimalFloatType => { IntOrFloat::DecimalFloatType => {
@ -7686,7 +7687,7 @@ fn from_can_pattern_help<'a>(
use crate::layout::UnionVariant::*; use crate::layout::UnionVariant::*;
let res_variant = 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); .map_err(Into::into);
let variant = match res_variant { let variant = match res_variant {
@ -7768,12 +7769,12 @@ fn from_can_pattern_help<'a>(
arguments.sort_by(|arg1, arg2| { arguments.sort_by(|arg1, arg2| {
let size1 = layout_cache let size1 = layout_cache
.from_var(env.arena, arg1.0, env.subs) .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); .unwrap_or(0);
let size2 = layout_cache let size2 = layout_cache
.from_var(env.arena, arg2.0, env.subs) .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); .unwrap_or(0);
size2.cmp(&size1) size2.cmp(&size1)
@ -7806,8 +7807,8 @@ fn from_can_pattern_help<'a>(
let layout2 = let layout2 =
layout_cache.from_var(env.arena, arg2.0, env.subs).unwrap(); layout_cache.from_var(env.arena, arg2.0, env.subs).unwrap();
let size1 = layout1.alignment_bytes(env.ptr_bytes); let size1 = layout1.alignment_bytes(env.target_info);
let size2 = layout2.alignment_bytes(env.ptr_bytes); let size2 = layout2.alignment_bytes(env.target_info);
size2.cmp(&size1) size2.cmp(&size1)
}); });
@ -8107,7 +8108,7 @@ fn from_can_pattern_help<'a>(
} => { } => {
// sorted fields based on the type // sorted fields based on the type
let sorted_fields = 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)?; .map_err(RuntimeError::from)?;
// sorted fields based on the destruct // 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 /// Given the `a` in `Num a`, determines whether it's an int or a float
pub fn num_argument_to_int_or_float( pub fn num_argument_to_int_or_float(
subs: &Subs, subs: &Subs,
ptr_bytes: u32, target_info: TargetInfo,
var: Variable, var: Variable,
known_to_be_float: bool, known_to_be_float: bool,
) -> IntOrFloat { ) -> IntOrFloat {
@ -8274,7 +8275,7 @@ pub fn num_argument_to_int_or_float(
// Recurse on the second argument // Recurse on the second argument
let var = subs[args.variables().into_iter().next().unwrap()]; 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, _) => { other @ Content::Alias(symbol, args, _) => {
@ -8292,16 +8293,15 @@ pub fn num_argument_to_int_or_float(
// Recurse on the second argument // Recurse on the second argument
let var = subs[args.variables().into_iter().next().unwrap()]; 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_DECIMAL | Symbol::NUM_AT_DECIMAL => IntOrFloat::DecimalFloatType,
Symbol::NUM_NAT | Symbol::NUM_NATURAL | Symbol::NUM_AT_NATURAL => { Symbol::NUM_NAT | Symbol::NUM_NATURAL | Symbol::NUM_AT_NATURAL => {
let int_width = match ptr_bytes { let int_width = match target_info.ptr_width() {
4 => IntWidth::U32, roc_target::PtrWidth::Bytes4 => IntWidth::U32,
8 => IntWidth::U64, roc_target::PtrWidth::Bytes8 => IntWidth::U64,
_ => panic!("unsupported word size"),
}; };
IntOrFloat::Int(int_width) IntOrFloat::Int(int_width)

View file

@ -6,6 +6,7 @@ use roc_collections::all::{default_hasher, MutMap};
use roc_module::ident::{Lowercase, TagName}; use roc_module::ident::{Lowercase, TagName};
use roc_module::symbol::{Interns, Symbol}; use roc_module::symbol::{Interns, Symbol};
use roc_problem::can::RuntimeError; use roc_problem::can::RuntimeError;
use roc_target::{PtrWidth, TargetInfo};
use roc_types::subs::{ use roc_types::subs::{
Content, FlatType, RecordFields, Subs, UnionTags, UnsortedUnionTags, Variable, Content, FlatType, RecordFields, Subs, UnionTags, UnsortedUnionTags, Variable,
}; };
@ -123,7 +124,7 @@ impl<'a> RawFunctionLayout<'a> {
// Nat // Nat
Alias(Symbol::NUM_NAT, args, _) => { Alias(Symbol::NUM_NAT, args, _) => {
debug_assert!(args.is_empty()); 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( Alias(symbol, _, _) if symbol.is_builtin() => Ok(Self::ZeroArgumentThunk(
@ -158,7 +159,7 @@ impl<'a> RawFunctionLayout<'a> {
let ret = arena.alloc(ret); let ret = arena.alloc(ret);
let lambda_set = 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)) Ok(Self::Function(fn_args, lambda_set, ret))
} }
@ -360,37 +361,36 @@ impl<'a> UnionLayout<'a> {
Layout::Builtin(self.tag_id_builtin()) Layout::Builtin(self.tag_id_builtin())
} }
fn stores_tag_id_in_pointer_bits(tags: &[&[Layout<'a>]], ptr_bytes: u32) -> bool { fn stores_tag_id_in_pointer_bits(tags: &[&[Layout<'a>]], target_info: TargetInfo) -> bool {
tags.len() < ptr_bytes as usize tags.len() < target_info.ptr_width() as usize
} }
pub fn tag_id_pointer_bits_and_mask(ptr_bytes: u32) -> (usize, usize) { pub fn tag_id_pointer_bits_and_mask(target_info: TargetInfo) -> (usize, usize) {
match ptr_bytes { match target_info.ptr_width() {
8 => (3, 0b0000_0111), PtrWidth::Bytes8 => (3, 0b0000_0111),
4 => (2, 0b0000_0011), PtrWidth::Bytes4 => (2, 0b0000_0011),
_ => unreachable!(),
} }
} }
// i.e. it is not implicit and not stored in the pointer bits // 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 { match self {
UnionLayout::NonRecursive(_) => true, UnionLayout::NonRecursive(_) => true,
UnionLayout::Recursive(tags) UnionLayout::Recursive(tags)
| UnionLayout::NullableWrapped { | UnionLayout::NullableWrapped {
other_tags: tags, .. 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, 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 { match self {
UnionLayout::NonRecursive(_) => false, UnionLayout::NonRecursive(_) => false,
UnionLayout::Recursive(tags) UnionLayout::Recursive(tags)
| UnionLayout::NullableWrapped { | UnionLayout::NullableWrapped {
other_tags: tags, .. 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, UnionLayout::NonNullableUnwrapped(_) | UnionLayout::NullableUnwrapped { .. } => false,
} }
} }
@ -414,76 +414,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() tags.iter()
.map(|fields| Layout::Struct(fields).alignment_bytes(pointer_size)) .map(|fields| Layout::Struct(fields).alignment_bytes(target_info))
.max() .max()
.unwrap_or(0) .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 { let allocation = match self {
UnionLayout::NonRecursive(_) => unreachable!("not heap-allocated"), 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) => { UnionLayout::NonNullableUnwrapped(fields) => {
Layout::Struct(fields).alignment_bytes(pointer_size) Layout::Struct(fields).alignment_bytes(target_info)
} }
UnionLayout::NullableWrapped { other_tags, .. } => { UnionLayout::NullableWrapped { other_tags, .. } => {
Self::tags_alignment_bytes(other_tags, pointer_size) Self::tags_alignment_bytes(other_tags, target_info)
} }
UnionLayout::NullableUnwrapped { other_fields, .. } => { 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 // 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) /// 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) { pub fn data_size_and_alignment(&self, target_info: TargetInfo) -> (u32, u32) {
let id_data_layout = if self.stores_tag_id_as_data(pointer_size) { let id_data_layout = if self.stores_tag_id_as_data(target_info) {
Some(self.tag_id_layout()) Some(self.tag_id_layout())
} else { } else {
None 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. /// 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. /// 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> { pub fn data_size_without_tag_id(&self, target_info: TargetInfo) -> Option<u32> {
if !self.stores_tag_id_as_data(pointer_size) { if !self.stores_tag_id_as_data(target_info) {
return None; return None;
}; };
Some( Some(self.data_size_and_alignment_help_match(None, target_info).0)
self.data_size_and_alignment_help_match(None, pointer_size)
.0,
)
} }
fn data_size_and_alignment_help_match( fn data_size_and_alignment_help_match(
&self, &self,
id_data_layout: Option<Layout>, id_data_layout: Option<Layout>,
pointer_size: u32, target_info: TargetInfo,
) -> (u32, u32) { ) -> (u32, u32) {
match self { match self {
Self::NonRecursive(tags) => { 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::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::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::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::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)
} }
} }
} }
@ -491,7 +488,7 @@ impl<'a> UnionLayout<'a> {
fn data_size_and_alignment_help( fn data_size_and_alignment_help(
variant_field_layouts: &[&[Layout]], variant_field_layouts: &[&[Layout]],
id_data_layout: Option<Layout>, id_data_layout: Option<Layout>,
pointer_size: u32, target_info: TargetInfo,
) -> (u32, u32) { ) -> (u32, u32) {
let mut size = 0; let mut size = 0;
let mut alignment_bytes = 0; let mut alignment_bytes = 0;
@ -505,7 +502,7 @@ impl<'a> UnionLayout<'a> {
data = Layout::Struct(&fields_and_id); 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); alignment_bytes = alignment_bytes.max(variant_alignment);
size = size.max(variant_size); size = size.max(variant_size);
} }
@ -700,7 +697,7 @@ impl<'a> LambdaSet<'a> {
arena: &'a Bump, arena: &'a Bump,
subs: &Subs, subs: &Subs,
closure_var: Variable, closure_var: Variable,
ptr_bytes: u32, target_info: TargetInfo,
) -> Result<Self, LayoutProblem> { ) -> Result<Self, LayoutProblem> {
let mut tags = std::vec::Vec::new(); let mut tags = std::vec::Vec::new();
match roc_types::pretty_print::chase_ext_tag_union(subs, closure_var, &mut tags) { match roc_types::pretty_print::chase_ext_tag_union(subs, closure_var, &mut tags) {
@ -714,7 +711,7 @@ impl<'a> LambdaSet<'a> {
arena, arena,
subs, subs,
seen: Vec::new_in(arena), seen: Vec::new_in(arena),
ptr_bytes, target_info,
}; };
for (tag_name, variables) in tags.iter() { for (tag_name, variables) in tags.iter() {
@ -732,7 +729,7 @@ impl<'a> LambdaSet<'a> {
} }
let representation = let representation =
arena.alloc(Self::make_representation(arena, subs, tags, ptr_bytes)); arena.alloc(Self::make_representation(arena, subs, tags, target_info));
Ok(LambdaSet { Ok(LambdaSet {
set: set.into_bump_slice(), set: set.into_bump_slice(),
@ -755,10 +752,10 @@ impl<'a> LambdaSet<'a> {
arena: &'a Bump, arena: &'a Bump,
subs: &Subs, subs: &Subs,
tags: std::vec::Vec<(TagName, std::vec::Vec<Variable>)>, tags: std::vec::Vec<(TagName, std::vec::Vec<Variable>)>,
ptr_bytes: u32, target_info: TargetInfo,
) -> Layout<'a> { ) -> Layout<'a> {
// otherwise, this is a closure with a payload // 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::*; use UnionVariant::*;
match variant { match variant {
@ -798,8 +795,8 @@ impl<'a> LambdaSet<'a> {
} }
} }
pub fn stack_size(&self, pointer_size: u32) -> u32 { pub fn stack_size(&self, target_info: TargetInfo) -> u32 {
self.representation.stack_size(pointer_size) self.representation.stack_size(target_info)
} }
pub fn contains_refcounted(&self) -> bool { pub fn contains_refcounted(&self) -> bool {
self.representation.contains_refcounted() self.representation.contains_refcounted()
@ -808,8 +805,8 @@ impl<'a> LambdaSet<'a> {
self.representation.safe_to_memcpy() self.representation.safe_to_memcpy()
} }
pub fn alignment_bytes(&self, pointer_size: u32) -> u32 { pub fn alignment_bytes(&self, target_info: TargetInfo) -> u32 {
self.representation.alignment_bytes(pointer_size) self.representation.alignment_bytes(target_info)
} }
} }
@ -826,7 +823,7 @@ pub enum Builtin<'a> {
} }
pub struct Env<'a, 'b> { pub struct Env<'a, 'b> {
ptr_bytes: u32, target_info: TargetInfo,
arena: &'a Bump, arena: &'a Bump,
seen: Vec<'a, Variable>, seen: Vec<'a, Variable>,
subs: &'b Subs, subs: &'b Subs,
@ -898,7 +895,7 @@ impl<'a> Layout<'a> {
} }
Symbol::NUM_NAT | Symbol::NUM_NATURAL | Symbol::NUM_AT_NATURAL => { 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), _ => Self::from_var(env, actual_var),
@ -970,31 +967,31 @@ impl<'a> Layout<'a> {
} }
} }
pub fn stack_size(&self, pointer_size: u32) -> u32 { pub fn stack_size(&self, target_info: TargetInfo) -> u32 {
let width = self.stack_size_without_alignment(pointer_size); let width = self.stack_size_without_alignment(target_info);
let alignment = self.alignment_bytes(pointer_size); let alignment = self.alignment_bytes(target_info);
round_up_to_alignment(width, alignment) round_up_to_alignment(width, alignment)
} }
pub fn stack_size_and_alignment(&self, pointer_size: u32) -> (u32, u32) { pub fn stack_size_and_alignment(&self, target_info: TargetInfo) -> (u32, u32) {
let width = self.stack_size_without_alignment(pointer_size); let width = self.stack_size_without_alignment(target_info);
let alignment = self.alignment_bytes(pointer_size); let alignment = self.alignment_bytes(target_info);
let size = round_up_to_alignment(width, alignment); let size = round_up_to_alignment(width, alignment);
(size, 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::*; use Layout::*;
match self { match self {
Builtin(builtin) => builtin.stack_size(pointer_size), Builtin(builtin) => builtin.stack_size(target_info),
Struct(fields) => { Struct(fields) => {
let mut sum = 0; let mut sum = 0;
for field_layout in *fields { for field_layout in *fields {
sum += field_layout.stack_size(pointer_size); sum += field_layout.stack_size(target_info);
} }
sum sum
@ -1003,26 +1000,26 @@ impl<'a> Layout<'a> {
use UnionLayout::*; use UnionLayout::*;
match variant { match variant {
NonRecursive(_) => variant.data_size_and_alignment(pointer_size).0, NonRecursive(_) => variant.data_size_and_alignment(target_info).0,
Recursive(_) Recursive(_)
| NullableWrapped { .. } | NullableWrapped { .. }
| NullableUnwrapped { .. } | NullableUnwrapped { .. }
| NonNullableUnwrapped(_) => pointer_size, | NonNullableUnwrapped(_) => target_info.ptr_width() as u32,
} }
} }
LambdaSet(lambda_set) => lambda_set LambdaSet(lambda_set) => lambda_set
.runtime_representation() .runtime_representation()
.stack_size_without_alignment(pointer_size), .stack_size_without_alignment(target_info),
RecursivePointer => pointer_size, 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 { match self {
Layout::Struct(fields) => fields Layout::Struct(fields) => fields
.iter() .iter()
.map(|x| x.alignment_bytes(pointer_size)) .map(|x| x.alignment_bytes(target_info))
.max() .max()
.unwrap_or(0), .unwrap_or(0),
@ -1036,44 +1033,44 @@ impl<'a> Layout<'a> {
.flat_map(|layouts| { .flat_map(|layouts| {
layouts layouts
.iter() .iter()
.map(|layout| layout.alignment_bytes(pointer_size)) .map(|layout| layout.alignment_bytes(target_info))
}) })
.max(); .max();
let tag_id_builtin = variant.tag_id_builtin(); let tag_id_builtin = variant.tag_id_builtin();
match max_alignment { match max_alignment {
Some(align) => round_up_to_alignment( Some(align) => round_up_to_alignment(
align.max(tag_id_builtin.alignment_bytes(pointer_size)), align.max(tag_id_builtin.alignment_bytes(target_info)),
tag_id_builtin.alignment_bytes(pointer_size), tag_id_builtin.alignment_bytes(target_info),
), ),
None => { None => {
// none of the tags had any payload, but the tag id still contains information // 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(_) Recursive(_)
| NullableWrapped { .. } | NullableWrapped { .. }
| NullableUnwrapped { .. } | NullableUnwrapped { .. }
| NonNullableUnwrapped(_) => pointer_size, | NonNullableUnwrapped(_) => target_info.ptr_width() as u32,
} }
} }
Layout::LambdaSet(lambda_set) => lambda_set Layout::LambdaSet(lambda_set) => lambda_set
.runtime_representation() .runtime_representation()
.alignment_bytes(pointer_size), .alignment_bytes(target_info),
Layout::Builtin(builtin) => builtin.alignment_bytes(pointer_size), Layout::Builtin(builtin) => builtin.alignment_bytes(target_info),
Layout::RecursivePointer => pointer_size, 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 { 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::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 Layout::LambdaSet(lambda_set) => lambda_set
.runtime_representation() .runtime_representation()
.allocation_alignment_bytes(pointer_size), .allocation_alignment_bytes(target_info),
Layout::RecursivePointer => unreachable!("should be looked up to get an actual layout"), Layout::RecursivePointer => unreachable!("should be looked up to get an actual layout"),
} }
} }
@ -1157,7 +1154,7 @@ impl<'a> Layout<'a> {
/// But if we're careful when to invalidate certain keys, we still get some benefit /// But if we're careful when to invalidate certain keys, we still get some benefit
#[derive(Debug)] #[derive(Debug)]
pub struct LayoutCache<'a> { pub struct LayoutCache<'a> {
ptr_bytes: u32, target_info: TargetInfo,
_marker: std::marker::PhantomData<&'a u8>, _marker: std::marker::PhantomData<&'a u8>,
} }
@ -1169,9 +1166,9 @@ pub enum CachedLayout<'a> {
} }
impl<'a> LayoutCache<'a> { impl<'a> LayoutCache<'a> {
pub fn new(ptr_bytes: u32) -> Self { pub fn new(target_info: TargetInfo) -> Self {
Self { Self {
ptr_bytes, target_info,
_marker: Default::default(), _marker: Default::default(),
} }
} }
@ -1189,7 +1186,7 @@ impl<'a> LayoutCache<'a> {
arena, arena,
subs, subs,
seen: Vec::new_in(arena), seen: Vec::new_in(arena),
ptr_bytes: self.ptr_bytes, target_info: self.target_info,
}; };
Layout::from_var(&mut env, var) Layout::from_var(&mut env, var)
@ -1208,7 +1205,7 @@ impl<'a> LayoutCache<'a> {
arena, arena,
subs, subs,
seen: Vec::new_in(arena), seen: Vec::new_in(arena),
ptr_bytes: self.ptr_bytes, target_info: self.target_info,
}; };
RawFunctionLayout::from_var(&mut env, var) RawFunctionLayout::from_var(&mut env, var)
} }
@ -1240,11 +1237,17 @@ impl<'a> Layout<'a> {
Layout::Builtin(Builtin::Float(FloatWidth::F32)) Layout::Builtin(Builtin::Float(FloatWidth::F32))
} }
pub fn usize(ptr_bytes: u32) -> Layout<'a> { pub fn usize(target_info: TargetInfo) -> Layout<'a> {
match ptr_bytes { match target_info.ptr_width() {
4 => Self::u32(), roc_target::PtrWidth::Bytes4 => Self::u32(),
8 => Self::u64(), roc_target::PtrWidth::Bytes8 => Self::u64(),
_ => panic!("width of usize {} not supported", ptr_bytes), }
}
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(),
} }
} }
@ -1318,42 +1321,46 @@ impl<'a> Builtin<'a> {
pub const WRAPPER_PTR: u32 = 0; pub const WRAPPER_PTR: u32 = 0;
pub const WRAPPER_LEN: u32 = 1; 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::*; use Builtin::*;
let ptr_width = target_info.ptr_width() as u32;
match self { match self {
Int(int) => int.stack_size(), Int(int) => int.stack_size(),
Float(float) => float.stack_size(), Float(float) => float.stack_size(),
Bool => Builtin::I1_SIZE, Bool => Builtin::I1_SIZE,
Decimal => Builtin::DECIMAL_SIZE, Decimal => Builtin::DECIMAL_SIZE,
Str => Builtin::STR_WORDS * pointer_size, Str => Builtin::STR_WORDS * ptr_width,
Dict(_, _) => Builtin::DICT_WORDS * pointer_size, Dict(_, _) => Builtin::DICT_WORDS * ptr_width,
Set(_) => Builtin::SET_WORDS * pointer_size, Set(_) => Builtin::SET_WORDS * ptr_width,
List(_) => Builtin::LIST_WORDS * pointer_size, 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 std::mem::align_of;
use Builtin::*; 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 // 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 // since both of those are one pointer size, the alignment of that structure is a pointer
// size // size
match self { match self {
Int(int_width) => int_width.alignment_bytes(), Int(int_width) => int_width.alignment_bytes(target_info),
Float(float_width) => float_width.alignment_bytes(), Float(float_width) => float_width.alignment_bytes(target_info),
Bool => align_of::<bool>() as u32, Bool => align_of::<bool>() as u32,
Decimal => align_of::<i128>() as u32, Decimal => IntWidth::I128.alignment_bytes(target_info),
Dict(_, _) => pointer_size, Dict(_, _) => ptr_width,
Set(_) => pointer_size, Set(_) => ptr_width,
// we often treat these as i128 (64-bit systems) // we often treat these as i128 (64-bit systems)
// or i64 (32-bit systems). // or i64 (32-bit systems).
// //
// In webassembly, For that to be safe // In webassembly, For that to be safe
// they must be aligned to allow such access // they must be aligned to allow such access
List(_) => pointer_size, List(_) => ptr_width,
Str => pointer_size, Str => ptr_width,
} }
} }
@ -1433,21 +1440,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 { let allocation = match self {
Builtin::Int(_) | Builtin::Float(_) | Builtin::Bool | Builtin::Decimal => { Builtin::Int(_) | Builtin::Float(_) | Builtin::Bool | Builtin::Decimal => {
unreachable!("not heap-allocated") unreachable!("not heap-allocated")
} }
Builtin::Str => pointer_size, Builtin::Str => ptr_width,
Builtin::Dict(k, v) => k Builtin::Dict(k, v) => k
.alignment_bytes(pointer_size) .alignment_bytes(target_info)
.max(v.alignment_bytes(pointer_size)) .max(v.alignment_bytes(target_info))
.max(pointer_size), .max(ptr_width),
Builtin::Set(k) => k.alignment_bytes(pointer_size).max(pointer_size), Builtin::Set(k) => k.alignment_bytes(target_info).max(ptr_width),
Builtin::List(e) => e.alignment_bytes(pointer_size).max(pointer_size), Builtin::List(e) => e.alignment_bytes(target_info).max(ptr_width),
}; };
allocation.max(pointer_size) allocation.max(ptr_width)
} }
} }
@ -1459,7 +1468,7 @@ fn layout_from_flat_type<'a>(
let arena = env.arena; let arena = env.arena;
let subs = env.subs; let subs = env.subs;
let ptr_bytes = env.ptr_bytes; let target_info = env.target_info;
match flat_type { match flat_type {
Apply(symbol, args) => { Apply(symbol, args) => {
@ -1469,7 +1478,7 @@ fn layout_from_flat_type<'a>(
// Ints // Ints
Symbol::NUM_NAT => { Symbol::NUM_NAT => {
debug_assert_eq!(args.len(), 0); debug_assert_eq!(args.len(), 0);
Ok(Layout::usize(env.ptr_bytes)) Ok(Layout::usize(env.target_info))
} }
Symbol::NUM_I128 => { Symbol::NUM_I128 => {
@ -1535,7 +1544,7 @@ fn layout_from_flat_type<'a>(
let var = args[0]; let var = args[0];
let content = subs.get_content_without_compacting(var); 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)), Symbol::STR_STR => Ok(Layout::Builtin(Builtin::Str)),
@ -1551,7 +1560,8 @@ fn layout_from_flat_type<'a>(
} }
} }
Func(_, closure_var, _) => { 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)) Ok(Layout::LambdaSet(lambda_set))
} }
@ -1571,8 +1581,8 @@ fn layout_from_flat_type<'a>(
} }
pairs.sort_by(|(label1, layout1), (label2, layout2)| { pairs.sort_by(|(label1, layout1), (label2, layout2)| {
let size1 = layout1.alignment_bytes(ptr_bytes); let size1 = layout1.alignment_bytes(target_info);
let size2 = layout2.alignment_bytes(ptr_bytes); let size2 = layout2.alignment_bytes(target_info);
size2.cmp(&size1).then(label1.cmp(label2)) size2.cmp(&size1).then(label1.cmp(label2))
}); });
@ -1592,7 +1602,7 @@ fn layout_from_flat_type<'a>(
debug_assert!(ext_var_is_empty_tag_union(subs, ext_var)); 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) => { FunctionOrTagUnion(tag_name, _, ext_var) => {
debug_assert!( debug_assert!(
@ -1603,7 +1613,7 @@ fn layout_from_flat_type<'a>(
let union_tags = UnionTags::from_tag_name_index(tag_name); let union_tags = UnionTags::from_tag_name_index(tag_name);
let (tags, _) = union_tags.unsorted_tags_and_ext(subs, ext_var); 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) => { RecursiveTagUnion(rec_var, tags, ext_var) => {
let (tags, ext_var) = tags.unsorted_tags_and_ext(subs, ext_var); let (tags, ext_var) = tags.unsorted_tags_and_ext(subs, ext_var);
@ -1653,8 +1663,8 @@ fn layout_from_flat_type<'a>(
} }
tag_layout.sort_by(|layout1, layout2| { tag_layout.sort_by(|layout1, layout2| {
let size1 = layout1.alignment_bytes(ptr_bytes); let size1 = layout1.alignment_bytes(target_info);
let size2 = layout2.alignment_bytes(ptr_bytes); let size2 = layout2.alignment_bytes(target_info);
size2.cmp(&size1) size2.cmp(&size1)
}); });
@ -1699,13 +1709,13 @@ pub fn sort_record_fields<'a>(
arena: &'a Bump, arena: &'a Bump,
var: Variable, var: Variable,
subs: &Subs, subs: &Subs,
ptr_bytes: u32, target_info: TargetInfo,
) -> Result<Vec<'a, SortedField<'a>>, LayoutProblem> { ) -> Result<Vec<'a, SortedField<'a>>, LayoutProblem> {
let mut env = Env { let mut env = Env {
arena, arena,
subs, subs,
seen: Vec::new_in(arena), seen: Vec::new_in(arena),
ptr_bytes, target_info,
}; };
let (it, _) = match gather_fields_unsorted_iter(subs, RecordFields::empty(), var) { let (it, _) = match gather_fields_unsorted_iter(subs, RecordFields::empty(), var) {
@ -1724,7 +1734,7 @@ fn sort_record_fields_help<'a>(
env: &mut Env<'a, '_>, env: &mut Env<'a, '_>,
fields_map: impl Iterator<Item = (Lowercase, RecordField<Variable>)>, fields_map: impl Iterator<Item = (Lowercase, RecordField<Variable>)>,
) -> Result<Vec<'a, SortedField<'a>>, LayoutProblem> { ) -> Result<Vec<'a, SortedField<'a>>, LayoutProblem> {
let ptr_bytes = env.ptr_bytes; let target_info = env.target_info;
// Sort the fields by label // Sort the fields by label
let mut sorted_fields = Vec::with_capacity_in(fields_map.size_hint().0, env.arena); let mut sorted_fields = Vec::with_capacity_in(fields_map.size_hint().0, env.arena);
@ -1746,8 +1756,8 @@ fn sort_record_fields_help<'a>(
|(label1, _, res_layout1), (label2, _, res_layout2)| match res_layout1 { |(label1, _, res_layout1), (label2, _, res_layout2)| match res_layout1 {
Ok(layout1) | Err(layout1) => match res_layout2 { Ok(layout1) | Err(layout1) => match res_layout2 {
Ok(layout2) | Err(layout2) => { Ok(layout2) | Err(layout2) => {
let size1 = layout1.alignment_bytes(ptr_bytes); let size1 = layout1.alignment_bytes(target_info);
let size2 = layout2.alignment_bytes(ptr_bytes); let size2 = layout2.alignment_bytes(target_info);
size2.cmp(&size1).then(label1.cmp(label2)) size2.cmp(&size1).then(label1.cmp(label2))
} }
@ -1881,7 +1891,7 @@ pub fn union_sorted_tags<'a>(
arena: &'a Bump, arena: &'a Bump,
var: Variable, var: Variable,
subs: &Subs, subs: &Subs,
ptr_bytes: u32, target_info: TargetInfo,
) -> Result<UnionVariant<'a>, LayoutProblem> { ) -> Result<UnionVariant<'a>, LayoutProblem> {
let var = let var =
if let Content::RecursionVar { structure, .. } = subs.get_content_without_compacting(var) { if let Content::RecursionVar { structure, .. } = subs.get_content_without_compacting(var) {
@ -1894,7 +1904,7 @@ pub fn union_sorted_tags<'a>(
let result = match roc_types::pretty_print::chase_ext_tag_union(subs, var, &mut tags_vec) { let result = match roc_types::pretty_print::chase_ext_tag_union(subs, var, &mut tags_vec) {
Ok(()) | Err((_, Content::FlexVar(_))) | Err((_, Content::RecursionVar { .. })) => { Ok(()) | Err((_, Content::FlexVar(_))) | Err((_, Content::RecursionVar { .. })) => {
let opt_rec_var = get_recursion_var(subs, var); 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((_, Content::Error)) => return Err(LayoutProblem::Erroneous),
Err(other) => panic!("invalid content in tag union variable: {:?}", other), Err(other) => panic!("invalid content in tag union variable: {:?}", other),
@ -1928,7 +1938,7 @@ fn union_sorted_tags_help_new<'a>(
tags_list: &[(&'_ TagName, &[Variable])], tags_list: &[(&'_ TagName, &[Variable])],
opt_rec_var: Option<Variable>, opt_rec_var: Option<Variable>,
subs: &Subs, subs: &Subs,
ptr_bytes: u32, target_info: TargetInfo,
) -> UnionVariant<'a> { ) -> UnionVariant<'a> {
// sort up front; make sure the ordering stays intact! // sort up front; make sure the ordering stays intact!
let mut tags_list = Vec::from_iter_in(tags_list.iter(), arena); let mut tags_list = Vec::from_iter_in(tags_list.iter(), arena);
@ -1938,7 +1948,7 @@ fn union_sorted_tags_help_new<'a>(
arena, arena,
subs, subs,
seen: Vec::new_in(arena), seen: Vec::new_in(arena),
ptr_bytes, target_info,
}; };
match tags_list.len() { match tags_list.len() {
@ -1957,7 +1967,8 @@ fn union_sorted_tags_help_new<'a>(
match tag_name { match tag_name {
TagName::Private(Symbol::NUM_AT_NUM) => { TagName::Private(Symbol::NUM_AT_NUM) => {
let var = arguments[0]; 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 { for &var in arguments {
@ -1981,8 +1992,8 @@ fn union_sorted_tags_help_new<'a>(
} }
layouts.sort_by(|layout1, layout2| { layouts.sort_by(|layout1, layout2| {
let size1 = layout1.alignment_bytes(ptr_bytes); let size1 = layout1.alignment_bytes(target_info);
let size2 = layout2.alignment_bytes(ptr_bytes); let size2 = layout2.alignment_bytes(target_info);
size2.cmp(&size1) size2.cmp(&size1)
}); });
@ -2059,8 +2070,8 @@ fn union_sorted_tags_help_new<'a>(
} }
arg_layouts.sort_by(|layout1, layout2| { arg_layouts.sort_by(|layout1, layout2| {
let size1 = layout1.alignment_bytes(ptr_bytes); let size1 = layout1.alignment_bytes(target_info);
let size2 = layout2.alignment_bytes(ptr_bytes); let size2 = layout2.alignment_bytes(target_info);
size2.cmp(&size1) size2.cmp(&size1)
}); });
@ -2131,7 +2142,7 @@ pub fn union_sorted_tags_help<'a>(
mut tags_vec: std::vec::Vec<(TagName, std::vec::Vec<Variable>)>, mut tags_vec: std::vec::Vec<(TagName, std::vec::Vec<Variable>)>,
opt_rec_var: Option<Variable>, opt_rec_var: Option<Variable>,
subs: &Subs, subs: &Subs,
ptr_bytes: u32, target_info: TargetInfo,
) -> UnionVariant<'a> { ) -> UnionVariant<'a> {
// sort up front; make sure the ordering stays intact! // sort up front; make sure the ordering stays intact!
tags_vec.sort_unstable_by(|(a, _), (b, _)| a.cmp(b)); tags_vec.sort_unstable_by(|(a, _), (b, _)| a.cmp(b));
@ -2140,7 +2151,7 @@ pub fn union_sorted_tags_help<'a>(
arena, arena,
subs, subs,
seen: Vec::new_in(arena), seen: Vec::new_in(arena),
ptr_bytes, target_info,
}; };
match tags_vec.len() { match tags_vec.len() {
@ -2159,7 +2170,8 @@ pub fn union_sorted_tags_help<'a>(
match tag_name { match tag_name {
TagName::Private(Symbol::NUM_AT_NUM) => { TagName::Private(Symbol::NUM_AT_NUM) => {
layouts.push( 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"),
); );
} }
_ => { _ => {
@ -2189,8 +2201,8 @@ pub fn union_sorted_tags_help<'a>(
} }
layouts.sort_by(|layout1, layout2| { layouts.sort_by(|layout1, layout2| {
let size1 = layout1.alignment_bytes(ptr_bytes); let size1 = layout1.alignment_bytes(target_info);
let size2 = layout2.alignment_bytes(ptr_bytes); let size2 = layout2.alignment_bytes(target_info);
size2.cmp(&size1) size2.cmp(&size1)
}); });
@ -2272,8 +2284,8 @@ pub fn union_sorted_tags_help<'a>(
} }
arg_layouts.sort_by(|layout1, layout2| { arg_layouts.sort_by(|layout1, layout2| {
let size1 = layout1.alignment_bytes(ptr_bytes); let size1 = layout1.alignment_bytes(target_info);
let size2 = layout2.alignment_bytes(ptr_bytes); let size2 = layout2.alignment_bytes(target_info);
size2.cmp(&size1) size2.cmp(&size1)
}); });
@ -2343,20 +2355,20 @@ fn layout_from_newtype<'a>(
arena: &'a Bump, arena: &'a Bump,
tags: &UnsortedUnionTags, tags: &UnsortedUnionTags,
subs: &Subs, subs: &Subs,
ptr_bytes: u32, target_info: TargetInfo,
) -> Layout<'a> { ) -> Layout<'a> {
debug_assert!(tags.is_newtype_wrapper(subs)); debug_assert!(tags.is_newtype_wrapper(subs));
let (tag_name, var) = tags.get_newtype(subs); let (tag_name, var) = tags.get_newtype(subs);
if tag_name == &TagName::Private(Symbol::NUM_AT_NUM) { 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 { } else {
let mut env = Env { let mut env = Env {
arena, arena,
subs, subs,
seen: Vec::new_in(arena), seen: Vec::new_in(arena),
ptr_bytes, target_info,
}; };
match Layout::from_var(&mut env, var) { match Layout::from_var(&mut env, var) {
@ -2380,12 +2392,12 @@ fn layout_from_tag_union<'a>(
arena: &'a Bump, arena: &'a Bump,
tags: &UnsortedUnionTags, tags: &UnsortedUnionTags,
subs: &Subs, subs: &Subs,
ptr_bytes: u32, target_info: TargetInfo,
) -> Layout<'a> { ) -> Layout<'a> {
use UnionVariant::*; use UnionVariant::*;
if tags.is_newtype_wrapper(subs) { 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; let tags_vec = &tags.tags;
@ -2396,11 +2408,12 @@ fn layout_from_tag_union<'a>(
let &var = arguments.iter().next().unwrap(); 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 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 { match variant {
Never => Layout::VOID, Never => Layout::VOID,
@ -2498,12 +2511,13 @@ pub fn ext_var_is_empty_tag_union(_: &Subs, _: Variable) -> bool {
unreachable!(); 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::Content::*;
use roc_types::subs::FlatType::*; use roc_types::subs::FlatType::*;
let ptr_bytes = 8;
match content { match content {
RecursionVar { .. } => panic!("recursion var in num"), RecursionVar { .. } => panic!("recursion var in num"),
FlexVar(_) | RigidVar(_) => { FlexVar(_) | RigidVar(_) => {
@ -2515,7 +2529,7 @@ fn layout_from_num_content<'a>(content: &Content) -> Result<Layout<'a>, LayoutPr
} }
Structure(Apply(symbol, args)) => match *symbol { Structure(Apply(symbol, args)) => match *symbol {
// Ints // 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_INTEGER => Ok(Layout::i64()),
Symbol::NUM_I128 => Ok(Layout::i128()), Symbol::NUM_I128 => Ok(Layout::i128()),
@ -2558,7 +2572,7 @@ fn layout_from_num_content<'a>(content: &Content) -> Result<Layout<'a>, LayoutPr
fn unwrap_num_tag<'a>( fn unwrap_num_tag<'a>(
subs: &Subs, subs: &Subs,
var: Variable, var: Variable,
ptr_bytes: u32, target_info: TargetInfo,
) -> Result<Layout<'a>, LayoutProblem> { ) -> Result<Layout<'a>, LayoutProblem> {
match subs.get_content_without_compacting(var) { match subs.get_content_without_compacting(var) {
Content::Alias(Symbol::NUM_INTEGER, args, _) => { Content::Alias(Symbol::NUM_INTEGER, args, _) => {
@ -2583,7 +2597,7 @@ fn unwrap_num_tag<'a>(
Symbol::NUM_UNSIGNED32 => Layout::u32(), Symbol::NUM_UNSIGNED32 => Layout::u32(),
Symbol::NUM_UNSIGNED16 => Layout::u16(), Symbol::NUM_UNSIGNED16 => Layout::u16(),
Symbol::NUM_UNSIGNED8 => Layout::u8(), 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), _ => unreachable!("not a valid int variant: {:?} {:?}", symbol, args),
}; };
@ -2829,8 +2843,8 @@ mod test {
let layout = Layout::Union(UnionLayout::NonRecursive(&tt)); let layout = Layout::Union(UnionLayout::NonRecursive(&tt));
let ptr_width = 8; let target_info = TargetInfo::default_x86_64();
assert_eq!(layout.stack_size(ptr_width), 1); assert_eq!(layout.stack_size(target_info), 1);
assert_eq!(layout.alignment_bytes(ptr_width), 1); assert_eq!(layout.alignment_bytes(target_info), 1);
} }
} }

View file

@ -3,6 +3,7 @@ use roc_builtins::bitcode::{FloatWidth, IntWidth};
use roc_collections::all::MutMap; use roc_collections::all::MutMap;
use roc_module::ident::TagName; use roc_module::ident::TagName;
use roc_module::symbol::Symbol; use roc_module::symbol::Symbol;
use roc_target::TargetInfo;
use roc_types::subs::{Content, FlatType, Subs, Variable}; use roc_types::subs::{Content, FlatType, Subs, Variable};
use roc_types::types::RecordField; use roc_types::types::RecordField;
use std::collections::hash_map::Entry; use std::collections::hash_map::Entry;
@ -99,7 +100,7 @@ pub struct Layouts {
lambda_sets: Vec<LambdaSet>, lambda_sets: Vec<LambdaSet>,
symbols: Vec<Symbol>, symbols: Vec<Symbol>,
recursion_variable_to_structure_variable_map: MutMap<Variable, Index<Layout>>, recursion_variable_to_structure_variable_map: MutMap<Variable, Index<Layout>>,
usize_int_width: IntWidth, target_info: TargetInfo,
} }
pub struct FunctionLayout { pub struct FunctionLayout {
@ -402,7 +403,7 @@ impl Layouts {
const VOID_TUPLE: Index<(Layout, Layout)> = Index::new(0); const VOID_TUPLE: Index<(Layout, Layout)> = Index::new(0);
const UNIT_INDEX: Index<Layout> = Index::new(2); 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); let mut layouts = Vec::with_capacity(64);
layouts.push(Layout::VOID); layouts.push(Layout::VOID);
@ -420,7 +421,7 @@ impl Layouts {
lambda_sets: Vec::default(), lambda_sets: Vec::default(),
symbols: Vec::default(), symbols: Vec::default(),
recursion_variable_to_structure_variable_map: MutMap::default(), recursion_variable_to_structure_variable_map: MutMap::default(),
usize_int_width, target_info,
} }
} }
@ -443,7 +444,12 @@ impl Layouts {
} }
fn usize(&self) -> Layout { 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 { fn align_of_layout_index(&self, index: Index<Layout>) -> u16 {
@ -453,18 +459,23 @@ impl Layouts {
} }
fn align_of_layout(&self, layout: Layout) -> u16 { 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 { match layout {
Layout::Reserved => unreachable!(), Layout::Reserved => unreachable!(),
Layout::Int(int_width) => int_width.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() as u16, Layout::Float(float_width) => float_width.alignment_bytes(self.target_info) as u16,
Layout::Decimal => IntWidth::U128.alignment_bytes() as u16, Layout::Decimal => IntWidth::U128.alignment_bytes(self.target_info) as u16,
Layout::Str | Layout::Dict(_) | Layout::Set(_) | Layout::List(_) => ptr_alignment, Layout::Str | Layout::Dict(_) | Layout::Set(_) | Layout::List(_) => ptr_alignment,
Layout::Struct(slice) => self.align_of_layout_slice(slice), Layout::Struct(slice) => self.align_of_layout_slice(slice),
Layout::Boxed(_) | Layout::UnionRecursive(_) => ptr_alignment, Layout::Boxed(_) | Layout::UnionRecursive(_) => ptr_alignment,
Layout::UnionNonRecursive(slices) => { 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) 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 { 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 { match layout {
Layout::Reserved => unreachable!(), Layout::Reserved => unreachable!(),

View 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"

View 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"),
}
}
}

View file

@ -21,6 +21,7 @@ roc_builtins = { path = "../builtins" }
roc_problem = { path = "../problem" } roc_problem = { path = "../problem" }
roc_parse = { path = "../parse" } roc_parse = { path = "../parse" }
roc_solve = { path = "../solve" } roc_solve = { path = "../solve" }
roc_target = { path = "../roc_target" }
pretty_assertions = "1.0.0" pretty_assertions = "1.0.0"
indoc = "1.0.3" indoc = "1.0.3"
tempfile = "3.2.0" tempfile = "3.2.0"

View file

@ -63,7 +63,7 @@ mod solve_expr {
&stdlib, &stdlib,
dir.path(), dir.path(),
exposed_types, exposed_types,
8, roc_target::TargetInfo::default_x86_64(),
builtin_defs_map, builtin_defs_map,
); );

View file

@ -31,6 +31,7 @@ roc_load = { path = "../load" }
roc_can = { path = "../can" } roc_can = { path = "../can" }
roc_parse = { path = "../parse" } roc_parse = { path = "../parse" }
roc_build = { path = "../build" } roc_build = { path = "../build" }
roc_target = { path = "../roc_target" }
roc_std = { path = "../../roc_std" } roc_std = { path = "../../roc_std" }
bumpalo = { version = "3.8.0", features = ["collections"] } bumpalo = { version = "3.8.0", features = ["collections"] }
either = "1.6.1" either = "1.6.1"

View file

@ -23,9 +23,9 @@ fn width_and_alignment_u8_u8() {
let layout = Layout::Union(UnionLayout::NonRecursive(&tt)); let layout = Layout::Union(UnionLayout::NonRecursive(&tt));
let ptr_width = 8; let target_info = roc_target::TargetInfo::default_x86_64();
assert_eq!(layout.alignment_bytes(ptr_width), 1); assert_eq!(layout.alignment_bytes(target_info), 1);
assert_eq!(layout.stack_size(ptr_width), 2); assert_eq!(layout.stack_size(target_info), 2);
} }
#[test] #[test]

View file

@ -57,7 +57,7 @@ pub fn helper(
&stdlib, &stdlib,
src_dir, src_dir,
exposed_types, exposed_types,
8, roc_target::TargetInfo::default_x86_64(),
builtin_defs_map, builtin_defs_map,
); );

View file

@ -42,6 +42,8 @@ fn create_llvm_module<'a>(
) -> (&'static str, String, &'a Module<'a>) { ) -> (&'static str, String, &'a Module<'a>) {
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
let target_info = roc_target::TargetInfo::from(target);
let filename = PathBuf::from("Test.roc"); let filename = PathBuf::from("Test.roc");
let src_dir = Path::new("fake/test/path"); let src_dir = Path::new("fake/test/path");
@ -56,8 +58,6 @@ fn create_llvm_module<'a>(
module_src = &temp; module_src = &temp;
} }
let ptr_bytes = target.pointer_width().unwrap().bytes() as u32;
let exposed_types = MutMap::default(); let exposed_types = MutMap::default();
let loaded = roc_load::file::load_and_monomorphize_from_str( let loaded = roc_load::file::load_and_monomorphize_from_str(
arena, arena,
@ -66,7 +66,7 @@ fn create_llvm_module<'a>(
stdlib, stdlib,
src_dir, src_dir,
exposed_types, exposed_types,
ptr_bytes, target_info,
test_builtin_defs, test_builtin_defs,
); );
@ -213,7 +213,7 @@ fn create_llvm_module<'a>(
context, context,
interns, interns,
module, module,
ptr_bytes, target_info,
is_gen_test, is_gen_test,
// important! we don't want any procedures to get the C calling convention // important! we don't want any procedures to get the C calling convention
exposed_to_host: MutSet::default(), exposed_to_host: MutSet::default(),

View file

@ -94,7 +94,6 @@ fn compile_roc_to_wasm_bytes<'a, T: Wasm32TestResult>(
} }
let exposed_types = MutMap::default(); let exposed_types = MutMap::default();
let ptr_bytes = 4;
let loaded = roc_load::file::load_and_monomorphize_from_str( let loaded = roc_load::file::load_and_monomorphize_from_str(
arena, arena,
filename, filename,
@ -102,7 +101,7 @@ fn compile_roc_to_wasm_bytes<'a, T: Wasm32TestResult>(
stdlib, stdlib,
src_dir, src_dir,
exposed_types, exposed_types,
ptr_bytes, roc_target::TargetInfo::default_wasm32(),
builtin_defs_map, builtin_defs_map,
); );

View file

@ -16,6 +16,7 @@ roc_builtins = { path = "../builtins" }
roc_load = { path = "../load" } roc_load = { path = "../load" }
roc_can = { path = "../can" } roc_can = { path = "../can" }
roc_mono = { path = "../mono" } roc_mono = { path = "../mono" }
roc_target = { path = "../roc_target" }
test_mono_macros = { path = "../test_mono_macros" } test_mono_macros = { path = "../test_mono_macros" }
pretty_assertions = "1.0.0" pretty_assertions = "1.0.0"
bumpalo = { version = "3.8.0", features = ["collections"] } bumpalo = { version = "3.8.0", features = ["collections"] }

View file

@ -25,6 +25,8 @@ use roc_mono::ir::Proc;
use roc_mono::ir::ProcLayout; 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 /// Without this, some tests pass in `cargo test --release` but fail without
/// the --release flag because they run out of stack space. This increases /// 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 /// 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, &stdlib,
src_dir, src_dir,
exposed_types, exposed_types,
8, TARGET_INFO,
builtin_defs_map, builtin_defs_map,
); );

View file

@ -18,6 +18,7 @@ roc_module = { path = "../compiler/module" }
roc_region = { path = "../compiler/region" } roc_region = { path = "../compiler/region" }
roc_types = { path = "../compiler/types" } roc_types = { path = "../compiler/types" }
roc_parse = { path = "../compiler/parse" } roc_parse = { path = "../compiler/parse" }
roc_target = { path = "../compiler/roc_target" }
roc_collections = { path = "../compiler/collections" } roc_collections = { path = "../compiler/collections" }
bumpalo = { version = "3.8.0", features = ["collections"] } bumpalo = { version = "3.8.0", features = ["collections"] }
snafu = { version = "0.6.10", features = ["backtraces"] } snafu = { version = "0.6.10", features = ["backtraces"] }

View file

@ -428,7 +428,7 @@ pub fn load_modules_for_files(filenames: Vec<PathBuf>, std_lib: StdLib) -> Vec<L
&std_lib, &std_lib,
src_dir.as_path(), src_dir.as_path(),
MutMap::default(), 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, builtin_defs_map,
) { ) {
Ok(loaded) => modules.push(loaded), Ok(loaded) => modules.push(loaded),

View file

@ -21,6 +21,22 @@ main =
|> Task.map (\_ -> {}) |> 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 ] 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 ]* divmod : I64, I64 -> Result { div : I64, mod : I64 } [ DivByZero ]*
@ -180,18 +196,6 @@ count = \expr ->
Ln f -> Ln f ->
count 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 : I64, Expr -> IO Expr
deriv = \i, f -> deriv = \i, f ->
fprime = d "x" f fprime = d "x" f

View file

@ -1,5 +1,5 @@
platform "folkertdev/foo" platform "folkertdev/foo"
requires { Model, Msg } { main : Effect {} } requires {} { main : Effect {} }
exposes [] exposes []
packages {} packages {}
imports [ Task.{ Task } ] imports [ Task.{ Task } ]

View file

@ -1 +1,3 @@
countdown
echo echo
form

View file

@ -1,16 +0,0 @@
app "echo"
packages { pf: "platform" }
imports [ pf.Task.{ Task, await }, pf.Stdout, pf.Stdin ]
provides [ main ] to pf
main : Task {} *
main =
{ } <- await (Stdout.line "What's your first name?")
firstName <- await Stdin.line
{ } <- await (Stdout.line "What's your last name?")
lastName <- await Stdin.line
Stdout.line "Hi, \(firstName) \(lastName)!"

View file

@ -0,0 +1,18 @@
app "countdown"
packages { pf: "platform" }
imports [ pf.Stdin, pf.Stdout, pf.Task.{ await, loop, succeed } ]
provides [ main ] to pf
main =
_ <- await (Stdout.line "\nLet's count down from 10 together - all you have to do is press <ENTER>.")
_ <- await Stdin.line
loop 10 tick
tick = \n ->
if n == 0 then
_ <- await (Stdout.line "🎉 SURPRISE! Happy Birthday! 🎂")
succeed (Done {})
else
_ <- await (n |> Num.toStr |> \s -> "\(s)..." |> Stdout.line)
_ <- await Stdin.line
succeed (Step (n - 1))

33
examples/cli/echo.roc Normal file
View file

@ -0,0 +1,33 @@
app "echo"
packages { pf: "platform" }
imports [ pf.Stdin, pf.Stdout, pf.Task ]
provides [ main ] to pf
main : Task.Task {} []
main =
_ <- Task.await (Stdout.line "🗣 Shout into this cave and hear the echo! 👂👂👂")
Task.loop {} (\_ -> Task.map tick Step)
tick : Task.Task {} []
tick =
shout <- Task.await Stdin.line
Stdout.line (echo shout)
echo : Str -> Str
echo = \shout ->
silence = \length ->
spaceInUtf8 = 32
List.repeat length spaceInUtf8
shout
|> Str.toUtf8
|> List.mapWithIndex
(\i, _ ->
length = (List.len (Str.toUtf8 shout) - i)
phrase = (List.split (Str.toUtf8 shout) length).before
List.concat (silence (if i == 0 then 2 * length else length)) phrase)
|> List.join
|> Str.fromUtf8
|> Result.withDefault ""

12
examples/cli/form.roc Normal file
View file

@ -0,0 +1,12 @@
app "form"
packages { pf: "platform" }
imports [ pf.Stdin, pf.Stdout, pf.Task.{ await, Task } ]
provides [ main ] to pf
main : Task {} *
main =
_ <- await (Stdout.line "What's your first name?")
firstName <- await Stdin.line
_ <- await (Stdout.line "What's your last name?")
lastName <- await Stdin.line
Stdout.line "Hi, \(firstName) \(lastName)! 👋"

View file

@ -9,7 +9,7 @@ use std::ffi::CStr;
use std::os::raw::c_char; use std::os::raw::c_char;
extern "C" { extern "C" {
#[link_name = "roc__mainForHost_1_exposed"] #[link_name = "roc__mainForHost_1_exposed_generic"]
fn roc_main(output: *mut u8) -> (); fn roc_main(output: *mut u8) -> ();
#[link_name = "roc__mainForHost_size"] #[link_name = "roc__mainForHost_size"]

View file

@ -89,6 +89,10 @@ isWhitespace = \char ->
== 0x9# tab == 0x9# tab
interpretCtx : Context -> Task Context InterpreterErrors interpretCtx : Context -> Task Context InterpreterErrors
interpretCtx = \ctx -> interpretCtx = \ctx ->
Task.loop ctx interpretCtxLoop
interpretCtxLoop : Context -> Task [ Step Context, Done Context ] InterpreterErrors
interpretCtxLoop = \ctx ->
when ctx.state is when ctx.state is
Executing if Context.inWhileScope ctx -> Executing if Context.inWhileScope ctx ->
# Deal with the current while loop potentially looping. # Deal with the current while loop potentially looping.
@ -104,11 +108,11 @@ interpretCtx = \ctx ->
if n == 0 then if n == 0 then
newScope = { scope & whileInfo: None } 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 else
newScope = { scope & whileInfo: Some { state: InBody, body, cond } } 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 -> Err e ->
Task.fail e Task.fail e
@ -117,7 +121,7 @@ interpretCtx = \ctx ->
# Just rand the body. Run the condition again. # Just rand the body. Run the condition again.
newScope = { scope & whileInfo: Some { state: InCond, body, cond } } 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 -> None ->
Task.fail NoScope Task.fail NoScope
@ -131,7 +135,7 @@ interpretCtx = \ctx ->
when result is when result is
Ok (T val newCtx) -> Ok (T val newCtx) ->
execCtx <- Task.await (stepExecCtx newCtx val) execCtx <- Task.await (stepExecCtx newCtx val)
interpretCtx execCtx Task.succeed (Step execCtx)
Err NoScope -> Err NoScope ->
Task.fail NoScope Task.fail NoScope
@ -143,9 +147,9 @@ interpretCtx = \ctx ->
# If no scopes left, all execution complete. # If no scopes left, all execution complete.
if List.isEmpty dropCtx.scopes then if List.isEmpty dropCtx.scopes then
Task.succeed dropCtx Task.succeed (Done dropCtx)
else else
interpretCtx dropCtx Task.succeed (Step dropCtx)
InComment -> InComment ->
result <- Task.attempt (Context.getChar ctx) result <- Task.attempt (Context.getChar ctx)
@ -153,9 +157,9 @@ interpretCtx = \ctx ->
Ok (T val newCtx) -> Ok (T val newCtx) ->
if val == 0x7D then if val == 0x7D then
# `}` end of comment # `}` end of comment
interpretCtx { newCtx & state: Executing } Task.succeed (Step { newCtx & state: Executing })
else else
interpretCtx { newCtx & state: InComment } Task.succeed (Step { newCtx & state: InComment })
Err NoScope -> Err NoScope ->
Task.fail NoScope Task.fail NoScope
@ -174,13 +178,13 @@ interpretCtx = \ctx ->
# so this is make i64 mul by 10 then convert back to i32. # so this is make i64 mul by 10 then convert back to i32.
nextAccum = (10 * Num.intCast accum) + Num.intCast (val - 0x30) 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 else
# outside of number now, this needs to be executed. # outside of number now, this needs to be executed.
pushCtx = Context.pushStack newCtx (Number accum) pushCtx = Context.pushStack newCtx (Number accum)
execCtx <- Task.await (stepExecCtx { pushCtx & state: Executing } val) execCtx <- Task.await (stepExecCtx { pushCtx & state: Executing } val)
interpretCtx execCtx Task.succeed (Step execCtx)
Err NoScope -> Err NoScope ->
Task.fail NoScope Task.fail NoScope
@ -197,12 +201,12 @@ interpretCtx = \ctx ->
when Str.fromUtf8 bytes is when Str.fromUtf8 bytes is
Ok str -> Ok str ->
{ } <- Task.await (Stdout.raw str) { } <- Task.await (Stdout.raw str)
interpretCtx { newCtx & state: Executing } Task.succeed (Step { newCtx & state: Executing })
Err _ -> Err _ ->
Task.fail BadUtf8 Task.fail BadUtf8
else else
interpretCtx { newCtx & state: InString (List.append bytes val) } Task.succeed (Step { newCtx & state: InString (List.append bytes val) })
Err NoScope -> Err NoScope ->
Task.fail NoScope Task.fail NoScope
@ -216,17 +220,17 @@ interpretCtx = \ctx ->
Ok (T val newCtx) -> Ok (T val newCtx) ->
if val == 0x5B then if val == 0x5B then
# start of a nested lambda `[` # 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 else if val == 0x5D then
# `]` end of current lambda # `]` end of current lambda
if depth == 0 then if depth == 0 then
# end of all lambdas # end of all lambdas
interpretCtx (Context.pushStack { newCtx & state: Executing } (Lambda bytes)) Task.succeed (Step (Context.pushStack { newCtx & state: Executing } (Lambda bytes)))
else else
# end of nested lambda # 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 else
interpretCtx { newCtx & state: InLambda depth (List.append bytes val) } Task.succeed (Step { newCtx & state: InLambda depth (List.append bytes val) })
Err NoScope -> Err NoScope ->
Task.fail NoScope Task.fail NoScope
@ -252,14 +256,14 @@ interpretCtx = \ctx ->
when result2 is when result2 is
Ok a -> Ok a ->
interpretCtx a Task.succeed (Step a)
Err e -> Err e ->
Task.fail e Task.fail e
Ok (T 0x9F newCtx) -> Ok (T 0x9F newCtx) ->
# This is supposed to flush io buffers. We don't buffer, so it does nothing # This is supposed to flush io buffers. We don't buffer, so it does nothing
interpretCtx newCtx Task.succeed (Step newCtx)
Ok (T x _) -> Ok (T x _) ->
data = Num.toStr (Num.intCast x) data = Num.toStr (Num.intCast x)
@ -276,7 +280,7 @@ interpretCtx = \ctx ->
result <- Task.attempt (Context.getChar { ctx & state: Executing }) result <- Task.attempt (Context.getChar { ctx & state: Executing })
when result is when result is
Ok (T x newCtx) -> Ok (T x newCtx) ->
interpretCtx (Context.pushStack newCtx (Number (Num.intCast x))) Task.succeed (Step (Context.pushStack newCtx (Number (Num.intCast x))))
Err NoScope -> Err NoScope ->
Task.fail NoScope Task.fail NoScope

View file

@ -1,9 +1,27 @@
interface Task interface Task
exposes [ Task, succeed, fail, await, map, onFail, attempt, fromResult ] exposes [ Task, succeed, fail, await, map, onFail, attempt, fromResult, loop ]
imports [ fx.Effect ] imports [ fx.Effect ]
Task ok err : Effect.Effect (Result ok err) 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 -> Task val *
succeed = \val -> succeed = \val ->
Effect.always (Ok val) Effect.always (Ok val)

View file

@ -12,7 +12,7 @@ use std::io::{BufRead, BufReader, Read, Write};
use std::os::raw::c_char; use std::os::raw::c_char;
extern "C" { extern "C" {
#[link_name = "roc__mainForHost_1_exposed"] #[link_name = "roc__mainForHost_1_exposed_generic"]
fn roc_main(args: RocStr, output: *mut u8) -> (); fn roc_main(args: RocStr, output: *mut u8) -> ();
#[link_name = "roc__mainForHost_size"] #[link_name = "roc__mainForHost_size"]
@ -188,10 +188,16 @@ pub extern "C" fn roc_fx_closeFile(br_ptr: *mut BufReader<File>) {
#[no_mangle] #[no_mangle]
pub extern "C" fn roc_fx_openFile(name: ManuallyDrop<RocStr>) -> *mut BufReader<File> { pub extern "C" fn roc_fx_openFile(name: ManuallyDrop<RocStr>) -> *mut BufReader<File> {
let f = File::open(name.as_str()).expect("Unable to open file"); match File::open(name.as_str()) {
Ok(f) => {
let br = BufReader::new(f); let br = BufReader::new(f);
Box::into_raw(Box::new(br)) Box::into_raw(Box::new(br))
}
Err(_) => {
panic!("unable to open file {:?}", name)
}
}
} }
#[no_mangle] #[no_mangle]

1
examples/tui/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
tui

View file

@ -24,6 +24,7 @@ roc_constrain = { path = "../compiler/constrain" }
roc_builtins = { path = "../compiler/builtins" } roc_builtins = { path = "../compiler/builtins" }
roc_problem = { path = "../compiler/problem" } roc_problem = { path = "../compiler/problem" }
roc_parse = { path = "../compiler/parse" } roc_parse = { path = "../compiler/parse" }
roc_target = { path = "../compiler/roc_target" }
roc_test_utils = { path = "../test_utils" } roc_test_utils = { path = "../test_utils" }
pretty_assertions = "1.0.0" pretty_assertions = "1.0.0"
indoc = "1.0.3" indoc = "1.0.3"

View file

@ -96,8 +96,8 @@ mod test_reporting {
let mut update_mode_ids = UpdateModeIds::new(); let mut update_mode_ids = UpdateModeIds::new();
// Populate Procs and Subs, and get the low-level Expr from the canonical Expr // Populate Procs and Subs, and get the low-level Expr from the canonical Expr
let ptr_bytes = 8; let target_info = roc_target::TargetInfo::default_x86_64();
let mut layout_cache = LayoutCache::new(ptr_bytes); let mut layout_cache = LayoutCache::new(target_info);
let mut mono_env = roc_mono::ir::Env { let mut mono_env = roc_mono::ir::Env {
arena: &arena, arena: &arena,
subs: &mut subs, subs: &mut subs,
@ -105,7 +105,7 @@ mod test_reporting {
home, home,
ident_ids: &mut ident_ids, ident_ids: &mut ident_ids,
update_mode_ids: &mut update_mode_ids, update_mode_ids: &mut update_mode_ids,
ptr_bytes, target_info,
// call_specialization_counter=0 is reserved // call_specialization_counter=0 is reserved
call_specialization_counter: 1, call_specialization_counter: 1,
}; };