Merge remote-tracking branch 'origin/trunk' into add_loop_examples

This commit is contained in:
Folkert 2022-01-27 16:49:47 +01:00
commit 3ade77374a
59 changed files with 751 additions and 534 deletions

21
Cargo.lock generated
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -14,13 +14,14 @@ use roc_mono::layout::{
};
use roc_parse::ast::{AssignedField, Collection, Expr, StrLiteral};
use roc_region::all::{Loc, Region};
use roc_target::TargetInfo;
use roc_types::subs::{Content, FlatType, GetSubsSlice, RecordFields, Subs, UnionTags, Variable};
use std::cmp::{max_by_key, min_by_key};
struct Env<'a, 'env> {
arena: &'a Bump,
subs: &'env Subs,
ptr_bytes: u32,
target_info: TargetInfo,
interns: &'env Interns,
home: ModuleId,
}
@ -47,12 +48,12 @@ pub unsafe fn jit_to_ast<'a>(
interns: &'a Interns,
home: ModuleId,
subs: &'a Subs,
ptr_bytes: u32,
target_info: TargetInfo,
) -> Result<Expr<'a>, ToAstProblem> {
let env = Env {
arena,
subs,
ptr_bytes,
target_info,
interns,
home,
};
@ -172,7 +173,7 @@ fn get_tags_vars_and_variant<'a>(
let vars_of_tag: MutMap<_, _> = tags_vec.iter().cloned().collect();
let union_variant =
union_sorted_tags_help(env.arena, tags_vec, opt_rec_var, env.subs, env.ptr_bytes);
union_sorted_tags_help(env.arena, tags_vec, opt_rec_var, env.subs, env.target_info);
(vars_of_tag, union_variant)
}
@ -200,8 +201,12 @@ fn expr_of_tag<'a>(
/// Gets the tag ID of a union variant, assuming that the tag ID is stored alongside (after) the
/// tag data. The caller is expected to check that the tag ID is indeed stored this way.
fn tag_id_from_data(union_layout: UnionLayout, data_ptr: *const u8, ptr_bytes: u32) -> i64 {
let offset = union_layout.data_size_without_tag_id(ptr_bytes).unwrap();
fn tag_id_from_data(
union_layout: UnionLayout,
data_ptr: *const u8,
target_info: TargetInfo,
) -> i64 {
let offset = union_layout.data_size_without_tag_id(target_info).unwrap();
unsafe {
match union_layout.tag_id_builtin() {
@ -218,13 +223,12 @@ fn tag_id_from_data(union_layout: UnionLayout, data_ptr: *const u8, ptr_bytes: u
}
}
fn deref_ptr_of_ptr(ptr_of_ptr: *const u8, ptr_bytes: u32) -> *const u8 {
fn deref_ptr_of_ptr(ptr_of_ptr: *const u8, target_info: TargetInfo) -> *const u8 {
unsafe {
match ptr_bytes {
match target_info.ptr_width() {
// Our LLVM codegen represents pointers as i32/i64s.
4 => *(ptr_of_ptr as *const i32) as *const u8,
8 => *(ptr_of_ptr as *const i64) as *const u8,
_ => unreachable!(),
roc_target::PtrWidth::Bytes4 => *(ptr_of_ptr as *const i32) as *const u8,
roc_target::PtrWidth::Bytes8 => *(ptr_of_ptr as *const i64) as *const u8,
}
}
}
@ -236,20 +240,20 @@ fn deref_ptr_of_ptr(ptr_of_ptr: *const u8, ptr_bytes: u32) -> *const u8 {
fn tag_id_from_recursive_ptr(
union_layout: UnionLayout,
rec_ptr: *const u8,
ptr_bytes: u32,
target_info: TargetInfo,
) -> (i64, *const u8) {
let tag_in_ptr = union_layout.stores_tag_id_in_pointer(ptr_bytes);
let tag_in_ptr = union_layout.stores_tag_id_in_pointer(target_info);
if tag_in_ptr {
let masked_ptr_to_data = deref_ptr_of_ptr(rec_ptr, ptr_bytes) as i64;
let (tag_id_bits, tag_id_mask) = tag_pointer_tag_id_bits_and_mask(ptr_bytes);
let masked_ptr_to_data = deref_ptr_of_ptr(rec_ptr, target_info) as i64;
let (tag_id_bits, tag_id_mask) = tag_pointer_tag_id_bits_and_mask(target_info);
let tag_id = masked_ptr_to_data & (tag_id_mask as i64);
// Clear the tag ID data from the pointer
let ptr_to_data = ((masked_ptr_to_data >> tag_id_bits) << tag_id_bits) as *const u8;
(tag_id as i64, ptr_to_data)
} else {
let ptr_to_data = deref_ptr_of_ptr(rec_ptr, ptr_bytes);
let tag_id = tag_id_from_data(union_layout, ptr_to_data, ptr_bytes);
let ptr_to_data = deref_ptr_of_ptr(rec_ptr, target_info);
let tag_id = tag_id_from_data(union_layout, ptr_to_data, target_info);
(tag_id, ptr_to_data)
}
}
@ -388,7 +392,7 @@ fn jit_to_ast_help<'a>(
let fields = [Layout::u64(), *layout];
let layout = Layout::Struct(&fields);
let result_stack_size = layout.stack_size(env.ptr_bytes);
let result_stack_size = layout.stack_size(env.target_info);
run_jit_function_dynamic_type!(
lib,
@ -398,7 +402,7 @@ fn jit_to_ast_help<'a>(
)
}
Layout::Union(UnionLayout::NonRecursive(_)) => {
let size = layout.stack_size(env.ptr_bytes);
let size = layout.stack_size(env.target_info);
Ok(run_jit_function_dynamic_type!(
lib,
main_fn_name,
@ -412,7 +416,7 @@ fn jit_to_ast_help<'a>(
| Layout::Union(UnionLayout::NonNullableUnwrapped(_))
| Layout::Union(UnionLayout::NullableUnwrapped { .. })
| Layout::Union(UnionLayout::NullableWrapped { .. }) => {
let size = layout.stack_size(env.ptr_bytes);
let size = layout.stack_size(env.target_info);
Ok(run_jit_function_dynamic_type!(
lib,
main_fn_name,
@ -506,7 +510,7 @@ fn ptr_to_ast<'a>(
}
(_, Layout::Builtin(Builtin::List(elem_layout))) => {
// Turn the (ptr, len) wrapper struct into actual ptr and len values.
let len = unsafe { *(ptr.offset(env.ptr_bytes as isize) as *const usize) };
let len = unsafe { *(ptr.offset(env.target_info.ptr_width() as isize) as *const usize) };
let ptr = unsafe { *(ptr as *const *const u8) };
list_to_ast(env, ptr, len, elem_layout, content)
@ -573,7 +577,7 @@ fn ptr_to_ast<'a>(
// Because this is a `NonRecursive`, the tag ID is definitely after the data.
let tag_id =
tag_id_from_data(union_layout, ptr, env.ptr_bytes);
tag_id_from_data(union_layout, ptr, env.target_info);
// use the tag ID as an index, to get its name and layout of any arguments
let (tag_name, arg_layouts) =
@ -605,7 +609,7 @@ fn ptr_to_ast<'a>(
_ => unreachable!("any other variant would have a different layout"),
};
let (tag_id, ptr_to_data) = tag_id_from_recursive_ptr(*union_layout, ptr, env.ptr_bytes);
let (tag_id, ptr_to_data) = tag_id_from_recursive_ptr(*union_layout, ptr, env.target_info);
let (tag_name, arg_layouts) = &tags_and_layouts[tag_id as usize];
expr_of_tag(
@ -633,7 +637,7 @@ fn ptr_to_ast<'a>(
_ => unreachable!("any other variant would have a different layout"),
};
let ptr_to_data = deref_ptr_of_ptr(ptr, env.ptr_bytes);
let ptr_to_data = deref_ptr_of_ptr(ptr, env.target_info);
expr_of_tag(
env,
@ -663,7 +667,7 @@ fn ptr_to_ast<'a>(
_ => unreachable!("any other variant would have a different layout"),
};
let ptr_to_data = deref_ptr_of_ptr(ptr, env.ptr_bytes);
let ptr_to_data = deref_ptr_of_ptr(ptr, env.target_info);
if ptr_to_data.is_null() {
tag_name_to_expr(env, &nullable_name)
} else {
@ -694,11 +698,11 @@ fn ptr_to_ast<'a>(
_ => unreachable!("any other variant would have a different layout"),
};
let ptr_to_data = deref_ptr_of_ptr(ptr, env.ptr_bytes);
let ptr_to_data = deref_ptr_of_ptr(ptr, env.target_info);
if ptr_to_data.is_null() {
tag_name_to_expr(env, &nullable_name)
} else {
let (tag_id, ptr_to_data) = tag_id_from_recursive_ptr(*union_layout, ptr, env.ptr_bytes);
let (tag_id, ptr_to_data) = tag_id_from_recursive_ptr(*union_layout, ptr, env.target_info);
let tag_id = if tag_id > nullable_id.into() { tag_id - 1 } else { tag_id };
@ -749,7 +753,7 @@ fn list_to_ast<'a>(
let arena = env.arena;
let mut output = Vec::with_capacity_in(len, arena);
let elem_size = elem_layout.stack_size(env.ptr_bytes) as usize;
let elem_size = elem_layout.stack_size(env.target_info) as usize;
for index in 0..len {
let offset_bytes = index * elem_size;
@ -823,7 +827,7 @@ where
output.push(&*arena.alloc(loc_expr));
// Advance the field pointer to the next field.
field_ptr = unsafe { field_ptr.offset(layout.stack_size(env.ptr_bytes) as isize) };
field_ptr = unsafe { field_ptr.offset(layout.stack_size(env.target_info) as isize) };
}
output
@ -908,7 +912,7 @@ fn struct_to_ast<'a>(
// Advance the field pointer to the next field.
field_ptr =
unsafe { field_ptr.offset(field_layout.stack_size(env.ptr_bytes) as isize) };
unsafe { field_ptr.offset(field_layout.stack_size(env.target_info) as isize) };
}
let output = output.into_bump_slice();
@ -1083,8 +1087,13 @@ fn byte_to_ast<'a>(env: &Env<'a, '_>, value: u8, content: &Content) -> Expr<'a>
.map(|(a, b)| (a.clone(), b.to_vec()))
.collect();
let union_variant =
union_sorted_tags_help(env.arena, tags_vec, None, env.subs, env.ptr_bytes);
let union_variant = union_sorted_tags_help(
env.arena,
tags_vec,
None,
env.subs,
env.target_info,
);
match union_variant {
UnionVariant::ByteUnion(tagnames) => {

View File

@ -13,6 +13,7 @@ use roc_load::file::LoadingProblem;
use roc_mono::ir::OptLevel;
use roc_parse::parser::SyntaxError;
use roc_region::all::LineInfo;
use roc_target::TargetInfo;
use roc_types::pretty_print::{content_to_string, name_all_type_vars};
use std::path::{Path, PathBuf};
use std::str::from_utf8_unchecked;
@ -43,7 +44,7 @@ pub fn gen_and_eval<'a>(
let module_src = promote_expr_to_module(src_str);
let ptr_bytes = target.pointer_width().unwrap().bytes() as u32;
let target_info = TargetInfo::from(&target);
let exposed_types = MutMap::default();
let loaded = roc_load::file::load_and_monomorphize_from_str(
@ -53,7 +54,7 @@ pub fn gen_and_eval<'a>(
&stdlib,
src_dir,
exposed_types,
ptr_bytes,
target_info,
builtin_defs_map,
);
@ -133,7 +134,6 @@ pub fn gen_and_eval<'a>(
} else {
let context = Context::create();
let builder = context.create_builder();
let ptr_bytes = target.pointer_width().unwrap().bytes() as u32;
let module = arena.alloc(roc_gen_llvm::llvm::build::module_from_builtins(
&target, &context, "",
));
@ -181,7 +181,7 @@ pub fn gen_and_eval<'a>(
context: &context,
interns,
module,
ptr_bytes,
target_info,
is_gen_test: true, // so roc_panic is generated
// important! we don't want any procedures to get the C calling convention
exposed_to_host: MutSet::default(),
@ -237,7 +237,7 @@ pub fn gen_and_eval<'a>(
&env.interns,
home,
&subs,
ptr_bytes,
target_info,
)
};
let mut expr = roc_fmt::Buf::new_in(&arena);

View File

@ -421,9 +421,11 @@ mod cli_run {
macro_rules! benchmarks {
($($test_name:ident => $benchmark:expr,)+) => {
$(
#[test]
#[cfg_attr(not(debug_assertions), serial(benchmark))]
#[cfg(all(not(feature = "wasm32-cli-run"), not(feature = "i386-cli-run")))]
fn $test_name() {
let benchmark = $benchmark;
let file_name = examples_dir("benchmarks").join(benchmark.filename);

View File

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

View File

@ -235,7 +235,7 @@ pub fn gen_from_mono_module_llvm(
let code_gen_start = SystemTime::now();
// Generate the binary
let ptr_bytes = target.pointer_width().unwrap().bytes() as u32;
let target_info = roc_target::TargetInfo::from(target);
let context = Context::create();
let module = arena.alloc(module_from_builtins(target, &context, "app"));
@ -286,7 +286,7 @@ pub fn gen_from_mono_module_llvm(
context: &context,
interns: loaded.interns,
module,
ptr_bytes,
target_info,
// in gen_tests, the compiler provides roc_panic
// and sets up the setjump/longjump exception handling
is_gen_test: false,

View File

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

View File

@ -1,4 +1,5 @@
use roc_module::symbol::Symbol;
use roc_target::TargetInfo;
use std::ops::Index;
pub const BUILTINS_HOST_OBJ_PATH: &str = env!(
@ -46,14 +47,21 @@ impl FloatWidth {
}
}
pub const fn alignment_bytes(&self) -> u32 {
pub const fn alignment_bytes(&self, target_info: TargetInfo) -> u32 {
use roc_target::Architecture;
use std::mem::align_of;
use FloatWidth::*;
// TODO actually alignment is architecture-specific
match self {
F32 => align_of::<f32>() as u32,
F64 => align_of::<f64>() as u32,
F64 => match target_info.architecture {
Architecture::X86_64
| Architecture::Aarch64
| Architecture::Arm
| Architecture::Wasm32 => 8,
Architecture::X86_32 => 4,
},
F128 => align_of::<i128>() as u32,
}
}
@ -106,16 +114,22 @@ impl IntWidth {
}
}
pub const fn alignment_bytes(&self) -> u32 {
pub const fn alignment_bytes(&self, target_info: TargetInfo) -> u32 {
use roc_target::Architecture;
use std::mem::align_of;
use IntWidth::*;
// TODO actually alignment is architecture-specific
match self {
U8 | I8 => align_of::<i8>() as u32,
U16 | I16 => align_of::<i16>() as u32,
U32 | I32 => align_of::<i32>() as u32,
U64 | I64 => align_of::<i64>() as u32,
U64 | I64 => match target_info.architecture {
Architecture::X86_64
| Architecture::Aarch64
| Architecture::Arm
| Architecture::Wasm32 => 8,
Architecture::X86_32 => 4,
},
U128 | I128 => align_of::<i128>() as u32,
}
}

View File

@ -124,7 +124,11 @@ where
// This is a type alias
// the symbol should already be added to the scope when this module is canonicalized
debug_assert!(scope.contains_alias(symbol));
debug_assert!(
scope.contains_alias(symbol),
"apparently, {:?} is not actually a type alias",
symbol
);
// but now we know this symbol by a different identifier, so we still need to add it to
// the scope

View File

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

View File

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

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::{
single_register_builtins, single_register_floats, single_register_integers, Relocation,
};
@ -451,7 +451,7 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg> for X86_64SystemV {
fn returns_via_arg_pointer(ret_layout: &Layout) -> bool {
// TODO: This may need to be more complex/extended to fully support the calling convention.
// details here: https://github.com/hjl-tools/x86-psABI/wiki/x86-64-psABI-1.0.pdf
ret_layout.stack_size(PTR_SIZE) > 16
ret_layout.stack_size(TARGET_INFO) > 16
}
}
@ -775,7 +775,7 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg> for X86_64WindowsFastcall {
fn returns_via_arg_pointer(ret_layout: &Layout) -> bool {
// TODO: This is not fully correct there are some exceptions for "vector" types.
// details here: https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention?view=msvc-160#return-values
ret_layout.stack_size(PTR_SIZE) > 8
ret_layout.stack_size(TARGET_INFO) > 8
}
}

View File

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

View File

@ -63,6 +63,7 @@ use roc_mono::ir::{
ModifyRc, OptLevel, ProcLayout,
};
use roc_mono::layout::{Builtin, LambdaSet, Layout, LayoutIds, TagIdIntType, UnionLayout};
use roc_target::TargetInfo;
use target_lexicon::{Architecture, OperatingSystem, Triple};
/// This is for Inkwell's FunctionValue::verify - we want to know the verification
@ -166,7 +167,7 @@ pub struct Env<'a, 'ctx, 'env> {
pub compile_unit: &'env DICompileUnit<'ctx>,
pub module: &'ctx Module<'ctx>,
pub interns: Interns,
pub ptr_bytes: u32,
pub target_info: TargetInfo,
pub is_gen_test: bool,
pub exposed_to_host: MutSet<Symbol>,
}
@ -195,15 +196,9 @@ impl<'a, 'ctx, 'env> Env<'a, 'ctx, 'env> {
pub fn ptr_int(&self) -> IntType<'ctx> {
let ctx = self.context;
match self.ptr_bytes {
1 => ctx.i8_type(),
2 => ctx.i16_type(),
4 => ctx.i32_type(),
8 => ctx.i64_type(),
_ => panic!(
"Invalid target: Roc does't support compiling to {}-bit systems.",
self.ptr_bytes * 8
),
match self.target_info.ptr_width() {
roc_target::PtrWidth::Bytes4 => ctx.i32_type(),
roc_target::PtrWidth::Bytes8 => ctx.i64_type(),
}
}
@ -212,11 +207,11 @@ impl<'a, 'ctx, 'env> Env<'a, 'ctx, 'env> {
/// on 64-bit systems, this is i128
/// on 32-bit systems, this is i64
pub fn str_list_c_abi(&self) -> IntType<'ctx> {
crate::llvm::convert::str_list_int(self.context, self.ptr_bytes)
crate::llvm::convert::str_list_int(self.context, self.target_info)
}
pub fn small_str_bytes(&self) -> u32 {
self.ptr_bytes * 2
self.target_info.ptr_width() as u32 * 2
}
pub fn build_intrinsic_call(
@ -269,7 +264,7 @@ impl<'a, 'ctx, 'env> Env<'a, 'ctx, 'env> {
}
pub fn alignment_intvalue(&self, element_layout: &Layout<'a>) -> BasicValueEnum<'ctx> {
let alignment = element_layout.alignment_bytes(self.ptr_bytes);
let alignment = element_layout.alignment_bytes(self.target_info);
let alignment_iv = self.alignment_const(alignment);
alignment_iv.into()
@ -317,12 +312,9 @@ impl<'a, 'ctx, 'env> Env<'a, 'ctx, 'env> {
) -> CallSiteValue<'ctx> {
let false_val = self.context.bool_type().const_int(0, false);
let intrinsic_name = match self.ptr_bytes {
8 => LLVM_MEMSET_I64,
4 => LLVM_MEMSET_I32,
other => {
unreachable!("Unsupported number of ptr_bytes {:?}", other);
}
let intrinsic_name = match self.target_info.ptr_width() {
roc_target::PtrWidth::Bytes8 => LLVM_MEMSET_I64,
roc_target::PtrWidth::Bytes4 => LLVM_MEMSET_I32,
};
self.build_intrinsic_call(
@ -1438,7 +1430,7 @@ fn build_wrapped_tag<'a, 'ctx, 'env>(
let raw_data_ptr = allocate_tag(env, parent, reuse_allocation, union_layout, tags);
let struct_type = env.context.struct_type(&field_types, false);
if union_layout.stores_tag_id_as_data(env.ptr_bytes) {
if union_layout.stores_tag_id_as_data(env.target_info) {
let tag_id_ptr = builder
.build_struct_gep(raw_data_ptr, TAG_ID_INDEX, "tag_id_index")
.unwrap();
@ -1524,7 +1516,7 @@ pub fn build_tag<'a, 'ctx, 'env>(
UnionLayout::NonRecursive(tags) => {
debug_assert!(union_size > 1);
let internal_type = block_of_memory_slices(env.context, tags, env.ptr_bytes);
let internal_type = block_of_memory_slices(env.context, tags, env.target_info);
let tag_id_type = basic_type_from_layout(env, &tag_id_layout).into_int_type();
let wrapper_type = env
@ -1711,7 +1703,7 @@ pub fn build_tag<'a, 'ctx, 'env>(
other_fields,
} => {
let tag_struct_type =
block_of_memory_slices(env.context, &[other_fields], env.ptr_bytes);
block_of_memory_slices(env.context, &[other_fields], env.target_info);
if tag_id == *nullable_id as _ {
let output_type = tag_struct_type.ptr_type(AddressSpace::Generic);
@ -1788,7 +1780,7 @@ fn tag_pointer_set_tag_id<'a, 'ctx, 'env>(
pointer: PointerValue<'ctx>,
) -> PointerValue<'ctx> {
// we only have 3 bits, so can encode only 0..7 (or on 32-bit targets, 2 bits to encode 0..3)
debug_assert!((tag_id as u32) < env.ptr_bytes);
debug_assert!((tag_id as u32) < env.target_info.ptr_width() as u32);
let ptr_int = env.ptr_int();
@ -1801,11 +1793,10 @@ fn tag_pointer_set_tag_id<'a, 'ctx, 'env>(
.build_int_to_ptr(combined, pointer.get_type(), "to_ptr")
}
pub fn tag_pointer_tag_id_bits_and_mask(ptr_bytes: u32) -> (u64, u64) {
match ptr_bytes {
8 => (3, 0b0000_0111),
4 => (2, 0b0000_0011),
_ => unreachable!(),
pub fn tag_pointer_tag_id_bits_and_mask(target_info: TargetInfo) -> (u64, u64) {
match target_info.ptr_width() {
roc_target::PtrWidth::Bytes8 => (3, 0b0000_0111),
roc_target::PtrWidth::Bytes4 => (2, 0b0000_0011),
}
}
@ -1813,7 +1804,7 @@ pub fn tag_pointer_read_tag_id<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
pointer: PointerValue<'ctx>,
) -> IntValue<'ctx> {
let (_, mask) = tag_pointer_tag_id_bits_and_mask(env.ptr_bytes);
let (_, mask) = tag_pointer_tag_id_bits_and_mask(env.target_info);
let ptr_int = env.ptr_int();
let as_int = env.builder.build_ptr_to_int(pointer, ptr_int, "to_int");
@ -1831,7 +1822,7 @@ pub fn tag_pointer_clear_tag_id<'a, 'ctx, 'env>(
) -> PointerValue<'ctx> {
let ptr_int = env.ptr_int();
let (tag_id_bits_mask, _) = tag_pointer_tag_id_bits_and_mask(env.ptr_bytes);
let (tag_id_bits_mask, _) = tag_pointer_tag_id_bits_and_mask(env.target_info);
let as_int = env.builder.build_ptr_to_int(pointer, ptr_int, "to_int");
@ -1918,7 +1909,7 @@ pub fn get_tag_id<'a, 'ctx, 'env>(
UnionLayout::Recursive(_) => {
let argument_ptr = argument.into_pointer_value();
if union_layout.stores_tag_id_as_data(env.ptr_bytes) {
if union_layout.stores_tag_id_as_data(env.target_info) {
get_tag_id_wrapped(env, argument_ptr)
} else {
tag_pointer_read_tag_id(env, argument_ptr)
@ -1949,7 +1940,7 @@ pub fn get_tag_id<'a, 'ctx, 'env>(
{
env.builder.position_at_end(else_block);
let tag_id = if union_layout.stores_tag_id_as_data(env.ptr_bytes) {
let tag_id = if union_layout.stores_tag_id_as_data(env.target_info) {
get_tag_id_wrapped(env, argument_ptr)
} else {
tag_pointer_read_tag_id(env, argument_ptr)
@ -2057,12 +2048,12 @@ fn lookup_at_index_ptr2<'a, 'ctx, 'env>(
let result = if field_layout.is_passed_by_reference() {
let field_type = basic_type_from_layout(env, &field_layout);
let align_bytes = field_layout.alignment_bytes(env.ptr_bytes);
let align_bytes = field_layout.alignment_bytes(env.target_info);
let alloca = tag_alloca(env, field_type, "copied_tag");
if align_bytes > 0 {
let size = env
.ptr_int()
.const_int(field_layout.stack_size(env.ptr_bytes) as u64, false);
.const_int(field_layout.stack_size(env.target_info) as u64, false);
env.builder
.build_memcpy(alloca, align_bytes, elem_ptr, align_bytes, size)
@ -2095,8 +2086,8 @@ pub fn reserve_with_refcount<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
layout: &Layout<'a>,
) -> PointerValue<'ctx> {
let stack_size = layout.stack_size(env.ptr_bytes);
let alignment_bytes = layout.alignment_bytes(env.ptr_bytes);
let stack_size = layout.stack_size(env.target_info);
let alignment_bytes = layout.alignment_bytes(env.target_info);
let basic_type = basic_type_from_layout(env, layout);
@ -2108,9 +2099,9 @@ fn reserve_with_refcount_union_as_block_of_memory<'a, 'ctx, 'env>(
union_layout: UnionLayout<'a>,
fields: &[&[Layout<'a>]],
) -> PointerValue<'ctx> {
let ptr_bytes = env.ptr_bytes;
let ptr_bytes = env.target_info;
let block_type = block_of_memory_slices(env.context, fields, env.ptr_bytes);
let block_type = block_of_memory_slices(env.context, fields, env.target_info);
let basic_type = if union_layout.stores_tag_id_as_data(ptr_bytes) {
let tag_id_type = basic_type_from_layout(env, &union_layout.tag_id_layout());
@ -2124,17 +2115,17 @@ fn reserve_with_refcount_union_as_block_of_memory<'a, 'ctx, 'env>(
let mut stack_size = fields
.iter()
.map(|tag| tag.iter().map(|l| l.stack_size(env.ptr_bytes)).sum())
.map(|tag| tag.iter().map(|l| l.stack_size(env.target_info)).sum())
.max()
.unwrap_or_default();
if union_layout.stores_tag_id_as_data(ptr_bytes) {
stack_size += union_layout.tag_id_layout().stack_size(env.ptr_bytes);
stack_size += union_layout.tag_id_layout().stack_size(env.target_info);
}
let alignment_bytes = fields
.iter()
.map(|tag| tag.iter().map(|l| l.alignment_bytes(env.ptr_bytes)))
.map(|tag| tag.iter().map(|l| l.alignment_bytes(env.target_info)))
.flatten()
.max()
.unwrap_or(0);
@ -2154,7 +2145,7 @@ fn reserve_with_refcount_help<'a, 'ctx, 'env>(
let value_bytes_intvalue = len_type.const_int(stack_size as u64, false);
let rc1 = crate::llvm::refcounting::refcount_1(ctx, env.ptr_bytes);
let rc1 = crate::llvm::refcounting::refcount_1(ctx, env.target_info);
allocate_with_refcount_help(env, basic_type, alignment_bytes, value_bytes_intvalue, rc1)
}
@ -2182,8 +2173,9 @@ pub fn allocate_with_refcount_help<'a, 'ctx, 'env>(
let builder = env.builder;
let len_type = env.ptr_int();
let ptr_width_u32 = env.target_info.ptr_width() as u32;
let extra_bytes = alignment_bytes.max(env.ptr_bytes);
let extra_bytes = alignment_bytes.max(ptr_width_u32);
let ptr = {
// number of bytes we will allocated
@ -2208,8 +2200,8 @@ pub fn allocate_with_refcount_help<'a, 'ctx, 'env>(
.into_pointer_value();
let index = match extra_bytes {
n if n == env.ptr_bytes => 1,
n if n == 2 * env.ptr_bytes => 2,
n if n == ptr_width_u32 => 1,
n if n == 2 * ptr_width_u32 => 2,
_ => unreachable!("invalid extra_bytes, {}", extra_bytes),
};
@ -2228,11 +2220,11 @@ pub fn allocate_with_refcount_help<'a, 'ctx, 'env>(
};
let refcount_ptr = match extra_bytes {
n if n == env.ptr_bytes => {
n if n == ptr_width_u32 => {
// the allocated pointer is the same as the refcounted pointer
unsafe { PointerToRefcount::from_ptr(env, ptr) }
}
n if n == 2 * env.ptr_bytes => {
n if n == 2 * ptr_width_u32 => {
// the refcount is stored just before the start of the actual data
// but in this case (because of alignment) not at the start of the allocated buffer
PointerToRefcount::from_ptr_to_data(env, data_ptr)
@ -2283,14 +2275,15 @@ fn list_literal<'a, 'ctx, 'env>(
// if element_type.is_int_type() {
if false {
let element_type = element_type.into_int_type();
let element_width = element_layout.stack_size(env.ptr_bytes);
let element_width = element_layout.stack_size(env.target_info);
let size = list_length * element_width as usize;
let alignment = element_layout
.alignment_bytes(env.ptr_bytes)
.max(env.ptr_bytes);
.alignment_bytes(env.target_info)
.max(env.target_info.ptr_width() as u32);
let mut is_all_constant = true;
let zero_elements = (env.ptr_bytes as f64 / element_width as f64).ceil() as usize;
let zero_elements =
(env.target_info.ptr_width() as u8 as f64 / element_width as f64).ceil() as usize;
// runtime-evaluated elements
let mut runtime_evaluated_elements = Vec::with_capacity_in(list_length, env.arena);
@ -2471,12 +2464,12 @@ pub fn store_roc_value<'a, 'ctx, 'env>(
value: BasicValueEnum<'ctx>,
) {
if layout.is_passed_by_reference() {
let align_bytes = layout.alignment_bytes(env.ptr_bytes);
let align_bytes = layout.alignment_bytes(env.target_info);
if align_bytes > 0 {
let size = env
.ptr_int()
.const_int(layout.stack_size(env.ptr_bytes) as u64, false);
.const_int(layout.stack_size(env.target_info) as u64, false);
env.builder
.build_memcpy(
@ -2572,7 +2565,7 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>(
let destination = out_parameter.into_pointer_value();
if layout.is_passed_by_reference() {
let align_bytes = layout.alignment_bytes(env.ptr_bytes);
let align_bytes = layout.alignment_bytes(env.target_info);
if align_bytes > 0 {
let value_ptr = value.into_pointer_value();
@ -2585,7 +2578,7 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>(
} else {
let size = env
.ptr_int()
.const_int(layout.stack_size(env.ptr_bytes) as u64, false);
.const_int(layout.stack_size(env.target_info) as u64, false);
env.builder
.build_memcpy(
@ -2776,21 +2769,21 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>(
match layout {
Layout::Builtin(Builtin::List(element_layout)) => {
debug_assert!(value.is_struct_value());
let alignment = element_layout.alignment_bytes(env.ptr_bytes);
let alignment = element_layout.alignment_bytes(env.target_info);
build_list::decref(env, value.into_struct_value(), alignment);
}
Layout::Builtin(Builtin::Dict(key_layout, value_layout)) => {
debug_assert!(value.is_struct_value());
let alignment = key_layout
.alignment_bytes(env.ptr_bytes)
.max(value_layout.alignment_bytes(env.ptr_bytes));
.alignment_bytes(env.target_info)
.max(value_layout.alignment_bytes(env.target_info));
build_dict::decref(env, value.into_struct_value(), alignment);
}
Layout::Builtin(Builtin::Set(key_layout)) => {
debug_assert!(value.is_struct_value());
let alignment = key_layout.alignment_bytes(env.ptr_bytes);
let alignment = key_layout.alignment_bytes(env.target_info);
build_dict::decref(env, value.into_struct_value(), alignment);
}
@ -3408,7 +3401,7 @@ fn expose_function_to_host_help_c_abi_generic<'a, 'ctx, 'env>(
builder.position_at_end(entry);
let wrapped_layout = roc_result_layout(env.arena, return_layout, env.ptr_bytes);
let wrapped_layout = roc_result_layout(env.arena, return_layout, env.target_info);
call_roc_function(env, roc_function, &wrapped_layout, arguments_for_call)
} else {
call_roc_function(env, roc_function, &return_layout, arguments_for_call)
@ -3712,7 +3705,10 @@ fn expose_function_to_host_help_c_abi<'a, 'ctx, 'env>(
}
pub fn get_sjlj_buffer<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>) -> PointerValue<'ctx> {
let type_ = env.context.i8_type().array_type(5 * env.ptr_bytes);
let type_ = env
.context
.i8_type()
.array_type(5 * env.target_info.ptr_width() as u32);
let global = match env.module.get_global("roc_sjlj_buffer") {
Some(global) => global,
@ -3880,8 +3876,12 @@ fn make_exception_catcher<'a, 'ctx, 'env>(
function_value
}
fn roc_result_layout<'a>(arena: &'a Bump, return_layout: Layout<'a>, ptr_bytes: u32) -> Layout<'a> {
let elements = [Layout::u64(), Layout::usize(ptr_bytes), return_layout];
fn roc_result_layout<'a>(
arena: &'a Bump,
return_layout: Layout<'a>,
target_info: TargetInfo,
) -> Layout<'a> {
let elements = [Layout::u64(), Layout::usize(target_info), return_layout];
Layout::Struct(arena.alloc(elements))
}
@ -4315,12 +4315,12 @@ pub fn build_closure_caller<'a, 'ctx, 'env>(
let call_result = call_roc_function(env, evaluator, return_layout, &evaluator_arguments);
if return_layout.is_passed_by_reference() {
let align_bytes = return_layout.alignment_bytes(env.ptr_bytes);
let align_bytes = return_layout.alignment_bytes(env.target_info);
if align_bytes > 0 {
let size = env
.ptr_int()
.const_int(return_layout.stack_size(env.ptr_bytes) as u64, false);
.const_int(return_layout.stack_size(env.target_info) as u64, false);
env.builder
.build_memcpy(
@ -5006,7 +5006,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
Layout::Builtin(Builtin::List(element_layout)),
Layout::Builtin(Builtin::List(result_layout)),
) => {
let argument_layouts = &[Layout::usize(env.ptr_bytes), **element_layout];
let argument_layouts = &[Layout::usize(env.target_info), **element_layout];
let roc_function_call = roc_function_call(
env,
@ -6061,8 +6061,8 @@ fn run_low_level<'a, 'ctx, 'env>(
{
bd.position_at_end(throw_block);
match env.ptr_bytes {
8 => {
match env.target_info.ptr_width() {
roc_target::PtrWidth::Bytes8 => {
let fn_ptr_type = context
.void_type()
.fn_type(&[], false)
@ -6081,11 +6081,10 @@ fn run_low_level<'a, 'ctx, 'env>(
bd.build_unconditional_branch(then_block);
}
4 => {
roc_target::PtrWidth::Bytes4 => {
// temporary WASM implementation
throw_exception(env, "An expectation failed!");
}
_ => unreachable!(),
}
}
@ -6211,8 +6210,8 @@ impl CCReturn {
/// According to the C ABI, how should we return a value with the given layout?
fn to_cc_return<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>, layout: &Layout<'a>) -> CCReturn {
let return_size = layout.stack_size(env.ptr_bytes);
let pass_result_by_pointer = return_size > 2 * env.ptr_bytes;
let return_size = layout.stack_size(env.target_info);
let pass_result_by_pointer = return_size > 2 * env.target_info.ptr_width() as u32;
if return_size == 0 {
CCReturn::Void
@ -7131,7 +7130,9 @@ fn define_global_str_literal_ptr<'a, 'ctx, 'env>(
let ptr = unsafe {
env.builder.build_in_bounds_gep(
ptr,
&[env.ptr_int().const_int(env.ptr_bytes as u64, false)],
&[env
.ptr_int()
.const_int(env.target_info.ptr_width() as u64, false)],
"get_rc_ptr",
)
};
@ -7161,11 +7162,11 @@ fn define_global_str_literal<'a, 'ctx, 'env>(
Some(current) => current,
None => {
let size = message.bytes().len() + env.ptr_bytes as usize;
let size = message.bytes().len() + env.target_info.ptr_width() as usize;
let mut bytes = Vec::with_capacity_in(size, env.arena);
// insert NULL bytes for the refcount
for _ in 0..env.ptr_bytes {
for _ in 0..env.target_info.ptr_width() as usize {
bytes.push(env.context.i8_type().const_zero());
}
@ -7184,7 +7185,7 @@ fn define_global_str_literal<'a, 'ctx, 'env>(
// strings are NULL-terminated, which means we can't store the refcount (which is 8
// NULL bytes)
global.set_constant(true);
global.set_alignment(env.ptr_bytes);
global.set_alignment(env.target_info.ptr_width() as u32);
global.set_unnamed_addr(true);
global.set_linkage(inkwell::module::Linkage::Private);

View File

@ -17,14 +17,15 @@ use inkwell::AddressSpace;
use roc_builtins::bitcode;
use roc_module::symbol::Symbol;
use roc_mono::layout::{Builtin, Layout, LayoutIds};
use roc_target::TargetInfo;
#[repr(transparent)]
struct Alignment(u8);
impl Alignment {
fn from_key_value_layout(key: &Layout, value: &Layout, ptr_bytes: u32) -> Alignment {
let key_align = key.alignment_bytes(ptr_bytes);
let value_align = value.alignment_bytes(ptr_bytes);
fn from_key_value_layout(key: &Layout, value: &Layout, target_info: TargetInfo) -> Alignment {
let key_align = key.alignment_bytes(target_info);
let value_align = value.alignment_bytes(target_info);
let mut bits = key_align.max(value_align) as u8;
@ -105,15 +106,15 @@ pub fn dict_insert<'a, 'ctx, 'env>(
let key_width = env
.ptr_int()
.const_int(key_layout.stack_size(env.ptr_bytes) as u64, false);
.const_int(key_layout.stack_size(env.target_info) as u64, false);
let value_width = env
.ptr_int()
.const_int(value_layout.stack_size(env.ptr_bytes) as u64, false);
.const_int(value_layout.stack_size(env.target_info) as u64, false);
let result_ptr = builder.build_alloca(zig_dict_type(env), "result_ptr");
let alignment = Alignment::from_key_value_layout(key_layout, value_layout, env.ptr_bytes);
let alignment = Alignment::from_key_value_layout(key_layout, value_layout, env.target_info);
let alignment_iv = alignment.as_int_value(env.context);
let hash_fn = build_hash_wrapper(env, layout_ids, key_layout);
@ -162,15 +163,15 @@ pub fn dict_remove<'a, 'ctx, 'env>(
let key_width = env
.ptr_int()
.const_int(key_layout.stack_size(env.ptr_bytes) as u64, false);
.const_int(key_layout.stack_size(env.target_info) as u64, false);
let value_width = env
.ptr_int()
.const_int(value_layout.stack_size(env.ptr_bytes) as u64, false);
.const_int(value_layout.stack_size(env.target_info) as u64, false);
let result_ptr = builder.build_alloca(zig_dict_type(env), "result_ptr");
let alignment = Alignment::from_key_value_layout(key_layout, value_layout, env.ptr_bytes);
let alignment = Alignment::from_key_value_layout(key_layout, value_layout, env.target_info);
let alignment_iv = alignment.as_int_value(env.context);
let hash_fn = build_hash_wrapper(env, layout_ids, key_layout);
@ -218,13 +219,13 @@ pub fn dict_contains<'a, 'ctx, 'env>(
let key_width = env
.ptr_int()
.const_int(key_layout.stack_size(env.ptr_bytes) as u64, false);
.const_int(key_layout.stack_size(env.target_info) as u64, false);
let value_width = env
.ptr_int()
.const_int(value_layout.stack_size(env.ptr_bytes) as u64, false);
.const_int(value_layout.stack_size(env.target_info) as u64, false);
let alignment = Alignment::from_key_value_layout(key_layout, value_layout, env.ptr_bytes);
let alignment = Alignment::from_key_value_layout(key_layout, value_layout, env.target_info);
let alignment_iv = alignment.as_int_value(env.context);
let hash_fn = build_hash_wrapper(env, layout_ids, key_layout);
@ -264,13 +265,13 @@ pub fn dict_get<'a, 'ctx, 'env>(
let key_width = env
.ptr_int()
.const_int(key_layout.stack_size(env.ptr_bytes) as u64, false);
.const_int(key_layout.stack_size(env.target_info) as u64, false);
let value_width = env
.ptr_int()
.const_int(value_layout.stack_size(env.ptr_bytes) as u64, false);
.const_int(value_layout.stack_size(env.target_info) as u64, false);
let alignment = Alignment::from_key_value_layout(key_layout, value_layout, env.ptr_bytes);
let alignment = Alignment::from_key_value_layout(key_layout, value_layout, env.target_info);
let alignment_iv = alignment.as_int_value(env.context);
let hash_fn = build_hash_wrapper(env, layout_ids, key_layout);
@ -366,13 +367,13 @@ pub fn dict_elements_rc<'a, 'ctx, 'env>(
) {
let key_width = env
.ptr_int()
.const_int(key_layout.stack_size(env.ptr_bytes) as u64, false);
.const_int(key_layout.stack_size(env.target_info) as u64, false);
let value_width = env
.ptr_int()
.const_int(value_layout.stack_size(env.ptr_bytes) as u64, false);
.const_int(value_layout.stack_size(env.target_info) as u64, false);
let alignment = Alignment::from_key_value_layout(key_layout, value_layout, env.ptr_bytes);
let alignment = Alignment::from_key_value_layout(key_layout, value_layout, env.target_info);
let alignment_iv = alignment.as_int_value(env.context);
let (key_fn, value_fn) = match rc_operation {
@ -412,13 +413,13 @@ pub fn dict_keys<'a, 'ctx, 'env>(
let key_width = env
.ptr_int()
.const_int(key_layout.stack_size(env.ptr_bytes) as u64, false);
.const_int(key_layout.stack_size(env.target_info) as u64, false);
let value_width = env
.ptr_int()
.const_int(value_layout.stack_size(env.ptr_bytes) as u64, false);
.const_int(value_layout.stack_size(env.target_info) as u64, false);
let alignment = Alignment::from_key_value_layout(key_layout, value_layout, env.ptr_bytes);
let alignment = Alignment::from_key_value_layout(key_layout, value_layout, env.target_info);
let alignment_iv = alignment.as_int_value(env.context);
let inc_key_fn = build_inc_wrapper(env, layout_ids, key_layout);
@ -454,19 +455,18 @@ fn pass_dict_c_abi<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
dict: BasicValueEnum<'ctx>,
) -> BasicValueEnum<'ctx> {
match env.ptr_bytes {
4 => {
match env.target_info.ptr_width() {
roc_target::PtrWidth::Bytes4 => {
let target_type = env.context.custom_width_int_type(96).into();
complex_bitcast(env.builder, dict, target_type, "to_i96")
}
8 => {
roc_target::PtrWidth::Bytes8 => {
let dict_ptr = env.builder.build_alloca(zig_dict_type(env), "dict_ptr");
env.builder.build_store(dict_ptr, dict);
dict_ptr.into()
}
_ => unreachable!(),
}
}
@ -483,13 +483,13 @@ pub fn dict_union<'a, 'ctx, 'env>(
let key_width = env
.ptr_int()
.const_int(key_layout.stack_size(env.ptr_bytes) as u64, false);
.const_int(key_layout.stack_size(env.target_info) as u64, false);
let value_width = env
.ptr_int()
.const_int(value_layout.stack_size(env.ptr_bytes) as u64, false);
.const_int(value_layout.stack_size(env.target_info) as u64, false);
let alignment = Alignment::from_key_value_layout(key_layout, value_layout, env.ptr_bytes);
let alignment = Alignment::from_key_value_layout(key_layout, value_layout, env.target_info);
let alignment_iv = alignment.as_int_value(env.context);
let hash_fn = build_hash_wrapper(env, layout_ids, key_layout);
@ -576,13 +576,13 @@ fn dict_intersect_or_difference<'a, 'ctx, 'env>(
let key_width = env
.ptr_int()
.const_int(key_layout.stack_size(env.ptr_bytes) as u64, false);
.const_int(key_layout.stack_size(env.target_info) as u64, false);
let value_width = env
.ptr_int()
.const_int(value_layout.stack_size(env.ptr_bytes) as u64, false);
.const_int(value_layout.stack_size(env.target_info) as u64, false);
let alignment = Alignment::from_key_value_layout(key_layout, value_layout, env.ptr_bytes);
let alignment = Alignment::from_key_value_layout(key_layout, value_layout, env.target_info);
let alignment_iv = alignment.as_int_value(env.context);
let hash_fn = build_hash_wrapper(env, layout_ids, key_layout);
@ -631,7 +631,7 @@ pub fn dict_walk<'a, 'ctx, 'env>(
let accum_ptr = builder.build_alloca(accum_bt, "accum_ptr");
env.builder.build_store(accum_ptr, accum);
let alignment = Alignment::from_key_value_layout(key_layout, value_layout, env.ptr_bytes);
let alignment = Alignment::from_key_value_layout(key_layout, value_layout, env.target_info);
let alignment_iv = alignment.as_int_value(env.context);
let output_ptr = builder.build_alloca(accum_bt, "output_ptr");
@ -671,13 +671,13 @@ pub fn dict_values<'a, 'ctx, 'env>(
let key_width = env
.ptr_int()
.const_int(key_layout.stack_size(env.ptr_bytes) as u64, false);
.const_int(key_layout.stack_size(env.target_info) as u64, false);
let value_width = env
.ptr_int()
.const_int(value_layout.stack_size(env.ptr_bytes) as u64, false);
.const_int(value_layout.stack_size(env.target_info) as u64, false);
let alignment = Alignment::from_key_value_layout(key_layout, value_layout, env.ptr_bytes);
let alignment = Alignment::from_key_value_layout(key_layout, value_layout, env.target_info);
let alignment_iv = alignment.as_int_value(env.context);
let inc_value_fn = build_inc_wrapper(env, layout_ids, value_layout);
@ -729,14 +729,14 @@ pub fn set_from_list<'a, 'ctx, 'env>(
let key_width = env
.ptr_int()
.const_int(key_layout.stack_size(env.ptr_bytes) as u64, false);
.const_int(key_layout.stack_size(env.target_info) as u64, false);
let value_width = env.ptr_int().const_zero();
let result_alloca = builder.build_alloca(zig_dict_type(env), "result_alloca");
let alignment =
Alignment::from_key_value_layout(key_layout, &Layout::Struct(&[]), env.ptr_bytes);
Alignment::from_key_value_layout(key_layout, &Layout::Struct(&[]), env.target_info);
let alignment_iv = alignment.as_int_value(env.context);
let hash_fn = build_hash_wrapper(env, layout_ids, key_layout);

View File

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

View File

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

View File

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

View File

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

View File

@ -175,7 +175,9 @@ pub fn add_sjlj_roc_panic(env: &Env<'_, '_, '_>) {
let buffer = crate::llvm::build::get_sjlj_buffer(env);
// write our error message pointer
let index = env.ptr_int().const_int(3 * env.ptr_bytes as u64, false);
let index = env
.ptr_int()
.const_int(3 * env.target_info.ptr_width() as u64, false);
let message_buffer_raw =
unsafe { builder.build_gep(buffer, &[index], "raw_msg_buffer_ptr") };
let message_buffer = builder.build_bitcast(

View File

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

View File

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

View File

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

View File

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

View File

@ -6,20 +6,29 @@ pub mod wasm_module;
use bumpalo::{self, collections::Vec, Bump};
use roc_builtins::bitcode::IntWidth;
use roc_collections::all::{MutMap, MutSet};
use roc_module::low_level::LowLevelWrapperType;
use roc_module::symbol::{Interns, ModuleId, Symbol};
use roc_mono::code_gen_help::CodeGenHelp;
use roc_mono::ir::{Proc, ProcLayout};
use roc_mono::layout::LayoutIds;
use roc_target::TargetInfo;
use crate::backend::WasmBackend;
use crate::wasm_module::{
Align, CodeBuilder, Export, ExportType, LocalId, SymInfo, ValueType, WasmModule,
};
const PTR_SIZE: u32 = 4;
const TARGET_INFO: TargetInfo = TargetInfo::default_wasm32();
const PTR_SIZE: u32 = {
let value = TARGET_INFO.ptr_width() as u32;
// const assert that our pointer width is actually 4
// the code relies on the pointer width being exactly 4
assert!(value == 4);
value
};
const PTR_TYPE: ValueType = ValueType::I32;
pub const STACK_POINTER_GLOBAL_ID: u32 = 0;
@ -111,7 +120,7 @@ pub fn build_module_without_test_wrapper<'a>(
proc_symbols,
initial_module,
fn_index_offset,
CodeGenHelp::new(env.arena, IntWidth::I32, env.module_id),
CodeGenHelp::new(env.arena, TargetInfo::default_wasm32(), env.module_id),
);
if DEBUG_LOG_SETTINGS.user_procs_ir {

View File

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

View File

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

View File

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

View File

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

View File

@ -590,7 +590,9 @@ fn eq_list<'a>(
// let size = literal int
let size = root.create_symbol(ident_ids, "size");
let size_expr = Expr::Literal(Literal::Int(elem_layout.stack_size(root.ptr_size) as i128));
let size_expr = Expr::Literal(Literal::Int(
elem_layout.stack_size(root.target_info) as i128
));
let size_stmt = |next| Stmt::Let(size, size_expr, layout_isize, next);
// let list_size = len_1 * size

View File

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

View File

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

View File

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

View File

@ -6,6 +6,7 @@ use roc_collections::all::{default_hasher, MutMap};
use roc_module::ident::{Lowercase, TagName};
use roc_module::symbol::{Interns, Symbol};
use roc_problem::can::RuntimeError;
use roc_target::TargetInfo;
use roc_types::subs::{
Content, FlatType, RecordFields, Subs, UnionTags, UnsortedUnionTags, Variable,
};
@ -123,7 +124,7 @@ impl<'a> RawFunctionLayout<'a> {
// Nat
Alias(Symbol::NUM_NAT, args, _) => {
debug_assert!(args.is_empty());
Ok(Self::ZeroArgumentThunk(Layout::usize(env.ptr_bytes)))
Ok(Self::ZeroArgumentThunk(Layout::usize(env.target_info)))
}
Alias(symbol, _, _) if symbol.is_builtin() => Ok(Self::ZeroArgumentThunk(
@ -158,7 +159,7 @@ impl<'a> RawFunctionLayout<'a> {
let ret = arena.alloc(ret);
let lambda_set =
LambdaSet::from_var(env.arena, env.subs, closure_var, env.ptr_bytes)?;
LambdaSet::from_var(env.arena, env.subs, closure_var, env.target_info)?;
Ok(Self::Function(fn_args, lambda_set, ret))
}
@ -360,29 +361,29 @@ impl<'a> UnionLayout<'a> {
Layout::Builtin(self.tag_id_builtin())
}
fn stores_tag_id_in_pointer_bits(tags: &[&[Layout<'a>]], ptr_bytes: u32) -> bool {
tags.len() < ptr_bytes as usize
fn stores_tag_id_in_pointer_bits(tags: &[&[Layout<'a>]], target_info: TargetInfo) -> bool {
tags.len() < target_info.ptr_width() as usize
}
// i.e. it is not implicit and not stored in the pointer bits
pub fn stores_tag_id_as_data(&self, ptr_bytes: u32) -> bool {
pub fn stores_tag_id_as_data(&self, target_info: TargetInfo) -> bool {
match self {
UnionLayout::NonRecursive(_) => true,
UnionLayout::Recursive(tags)
| UnionLayout::NullableWrapped {
other_tags: tags, ..
} => !Self::stores_tag_id_in_pointer_bits(tags, ptr_bytes),
} => !Self::stores_tag_id_in_pointer_bits(tags, target_info),
UnionLayout::NonNullableUnwrapped(_) | UnionLayout::NullableUnwrapped { .. } => false,
}
}
pub fn stores_tag_id_in_pointer(&self, ptr_bytes: u32) -> bool {
pub fn stores_tag_id_in_pointer(&self, target_info: TargetInfo) -> bool {
match self {
UnionLayout::NonRecursive(_) => false,
UnionLayout::Recursive(tags)
| UnionLayout::NullableWrapped {
other_tags: tags, ..
} => Self::stores_tag_id_in_pointer_bits(tags, ptr_bytes),
} => Self::stores_tag_id_in_pointer_bits(tags, target_info),
UnionLayout::NonNullableUnwrapped(_) | UnionLayout::NullableUnwrapped { .. } => false,
}
}
@ -406,76 +407,73 @@ impl<'a> UnionLayout<'a> {
}
}
fn tags_alignment_bytes(tags: &[&[Layout]], pointer_size: u32) -> u32 {
fn tags_alignment_bytes(tags: &[&[Layout]], target_info: TargetInfo) -> u32 {
tags.iter()
.map(|fields| Layout::Struct(fields).alignment_bytes(pointer_size))
.map(|fields| Layout::Struct(fields).alignment_bytes(target_info))
.max()
.unwrap_or(0)
}
pub fn allocation_alignment_bytes(&self, pointer_size: u32) -> u32 {
pub fn allocation_alignment_bytes(&self, target_info: TargetInfo) -> u32 {
let allocation = match self {
UnionLayout::NonRecursive(_) => unreachable!("not heap-allocated"),
UnionLayout::Recursive(tags) => Self::tags_alignment_bytes(tags, pointer_size),
UnionLayout::Recursive(tags) => Self::tags_alignment_bytes(tags, target_info),
UnionLayout::NonNullableUnwrapped(fields) => {
Layout::Struct(fields).alignment_bytes(pointer_size)
Layout::Struct(fields).alignment_bytes(target_info)
}
UnionLayout::NullableWrapped { other_tags, .. } => {
Self::tags_alignment_bytes(other_tags, pointer_size)
Self::tags_alignment_bytes(other_tags, target_info)
}
UnionLayout::NullableUnwrapped { other_fields, .. } => {
Layout::Struct(other_fields).alignment_bytes(pointer_size)
Layout::Struct(other_fields).alignment_bytes(target_info)
}
};
// because we store a refcount, the alignment must be at least the size of a pointer
allocation.max(pointer_size)
allocation.max(target_info.ptr_width() as u32)
}
/// Size of the data in memory, whether it's stack or heap (for non-null tag ids)
pub fn data_size_and_alignment(&self, pointer_size: u32) -> (u32, u32) {
let id_data_layout = if self.stores_tag_id_as_data(pointer_size) {
pub fn data_size_and_alignment(&self, target_info: TargetInfo) -> (u32, u32) {
let id_data_layout = if self.stores_tag_id_as_data(target_info) {
Some(self.tag_id_layout())
} else {
None
};
self.data_size_and_alignment_help_match(id_data_layout, pointer_size)
self.data_size_and_alignment_help_match(id_data_layout, target_info)
}
/// Size of the data before the tag_id, if it exists.
/// Returns None if the tag_id is not stored as data in the layout.
pub fn data_size_without_tag_id(&self, pointer_size: u32) -> Option<u32> {
if !self.stores_tag_id_as_data(pointer_size) {
pub fn data_size_without_tag_id(&self, target_info: TargetInfo) -> Option<u32> {
if !self.stores_tag_id_as_data(target_info) {
return None;
};
Some(
self.data_size_and_alignment_help_match(None, pointer_size)
.0,
)
Some(self.data_size_and_alignment_help_match(None, target_info).0)
}
fn data_size_and_alignment_help_match(
&self,
id_data_layout: Option<Layout>,
pointer_size: u32,
target_info: TargetInfo,
) -> (u32, u32) {
match self {
Self::NonRecursive(tags) => {
Self::data_size_and_alignment_help(tags, id_data_layout, pointer_size)
Self::data_size_and_alignment_help(tags, id_data_layout, target_info)
}
Self::Recursive(tags) => {
Self::data_size_and_alignment_help(tags, id_data_layout, pointer_size)
Self::data_size_and_alignment_help(tags, id_data_layout, target_info)
}
Self::NonNullableUnwrapped(fields) => {
Self::data_size_and_alignment_help(&[fields], id_data_layout, pointer_size)
Self::data_size_and_alignment_help(&[fields], id_data_layout, target_info)
}
Self::NullableWrapped { other_tags, .. } => {
Self::data_size_and_alignment_help(other_tags, id_data_layout, pointer_size)
Self::data_size_and_alignment_help(other_tags, id_data_layout, target_info)
}
Self::NullableUnwrapped { other_fields, .. } => {
Self::data_size_and_alignment_help(&[other_fields], id_data_layout, pointer_size)
Self::data_size_and_alignment_help(&[other_fields], id_data_layout, target_info)
}
}
}
@ -483,7 +481,7 @@ impl<'a> UnionLayout<'a> {
fn data_size_and_alignment_help(
variant_field_layouts: &[&[Layout]],
id_data_layout: Option<Layout>,
pointer_size: u32,
target_info: TargetInfo,
) -> (u32, u32) {
let mut size = 0;
let mut alignment_bytes = 0;
@ -497,7 +495,7 @@ impl<'a> UnionLayout<'a> {
data = Layout::Struct(&fields_and_id);
}
let (variant_size, variant_alignment) = data.stack_size_and_alignment(pointer_size);
let (variant_size, variant_alignment) = data.stack_size_and_alignment(target_info);
alignment_bytes = alignment_bytes.max(variant_alignment);
size = size.max(variant_size);
}
@ -692,7 +690,7 @@ impl<'a> LambdaSet<'a> {
arena: &'a Bump,
subs: &Subs,
closure_var: Variable,
ptr_bytes: u32,
target_info: TargetInfo,
) -> Result<Self, LayoutProblem> {
let mut tags = std::vec::Vec::new();
match roc_types::pretty_print::chase_ext_tag_union(subs, closure_var, &mut tags) {
@ -706,7 +704,7 @@ impl<'a> LambdaSet<'a> {
arena,
subs,
seen: Vec::new_in(arena),
ptr_bytes,
target_info,
};
for (tag_name, variables) in tags.iter() {
@ -724,7 +722,7 @@ impl<'a> LambdaSet<'a> {
}
let representation =
arena.alloc(Self::make_representation(arena, subs, tags, ptr_bytes));
arena.alloc(Self::make_representation(arena, subs, tags, target_info));
Ok(LambdaSet {
set: set.into_bump_slice(),
@ -747,10 +745,10 @@ impl<'a> LambdaSet<'a> {
arena: &'a Bump,
subs: &Subs,
tags: std::vec::Vec<(TagName, std::vec::Vec<Variable>)>,
ptr_bytes: u32,
target_info: TargetInfo,
) -> Layout<'a> {
// otherwise, this is a closure with a payload
let variant = union_sorted_tags_help(arena, tags, None, subs, ptr_bytes);
let variant = union_sorted_tags_help(arena, tags, None, subs, target_info);
use UnionVariant::*;
match variant {
@ -790,8 +788,8 @@ impl<'a> LambdaSet<'a> {
}
}
pub fn stack_size(&self, pointer_size: u32) -> u32 {
self.representation.stack_size(pointer_size)
pub fn stack_size(&self, target_info: TargetInfo) -> u32 {
self.representation.stack_size(target_info)
}
pub fn contains_refcounted(&self) -> bool {
self.representation.contains_refcounted()
@ -800,8 +798,8 @@ impl<'a> LambdaSet<'a> {
self.representation.safe_to_memcpy()
}
pub fn alignment_bytes(&self, pointer_size: u32) -> u32 {
self.representation.alignment_bytes(pointer_size)
pub fn alignment_bytes(&self, target_info: TargetInfo) -> u32 {
self.representation.alignment_bytes(target_info)
}
}
@ -818,7 +816,7 @@ pub enum Builtin<'a> {
}
pub struct Env<'a, 'b> {
ptr_bytes: u32,
target_info: TargetInfo,
arena: &'a Bump,
seen: Vec<'a, Variable>,
subs: &'b Subs,
@ -890,7 +888,7 @@ impl<'a> Layout<'a> {
}
Symbol::NUM_NAT | Symbol::NUM_NATURAL | Symbol::NUM_AT_NATURAL => {
return Ok(Layout::usize(env.ptr_bytes))
return Ok(Layout::usize(env.target_info))
}
_ => Self::from_var(env, actual_var),
@ -962,31 +960,31 @@ impl<'a> Layout<'a> {
}
}
pub fn stack_size(&self, pointer_size: u32) -> u32 {
let width = self.stack_size_without_alignment(pointer_size);
let alignment = self.alignment_bytes(pointer_size);
pub fn stack_size(&self, target_info: TargetInfo) -> u32 {
let width = self.stack_size_without_alignment(target_info);
let alignment = self.alignment_bytes(target_info);
round_up_to_alignment(width, alignment)
}
pub fn stack_size_and_alignment(&self, pointer_size: u32) -> (u32, u32) {
let width = self.stack_size_without_alignment(pointer_size);
let alignment = self.alignment_bytes(pointer_size);
pub fn stack_size_and_alignment(&self, target_info: TargetInfo) -> (u32, u32) {
let width = self.stack_size_without_alignment(target_info);
let alignment = self.alignment_bytes(target_info);
let size = round_up_to_alignment(width, alignment);
(size, alignment)
}
fn stack_size_without_alignment(&self, pointer_size: u32) -> u32 {
fn stack_size_without_alignment(&self, target_info: TargetInfo) -> u32 {
use Layout::*;
match self {
Builtin(builtin) => builtin.stack_size(pointer_size),
Builtin(builtin) => builtin.stack_size(target_info),
Struct(fields) => {
let mut sum = 0;
for field_layout in *fields {
sum += field_layout.stack_size(pointer_size);
sum += field_layout.stack_size(target_info);
}
sum
@ -995,26 +993,26 @@ impl<'a> Layout<'a> {
use UnionLayout::*;
match variant {
NonRecursive(_) => variant.data_size_and_alignment(pointer_size).0,
NonRecursive(_) => variant.data_size_and_alignment(target_info).0,
Recursive(_)
| NullableWrapped { .. }
| NullableUnwrapped { .. }
| NonNullableUnwrapped(_) => pointer_size,
| NonNullableUnwrapped(_) => target_info.ptr_width() as u32,
}
}
LambdaSet(lambda_set) => lambda_set
.runtime_representation()
.stack_size_without_alignment(pointer_size),
RecursivePointer => pointer_size,
.stack_size_without_alignment(target_info),
RecursivePointer => target_info.ptr_width() as u32,
}
}
pub fn alignment_bytes(&self, pointer_size: u32) -> u32 {
pub fn alignment_bytes(&self, target_info: TargetInfo) -> u32 {
match self {
Layout::Struct(fields) => fields
.iter()
.map(|x| x.alignment_bytes(pointer_size))
.map(|x| x.alignment_bytes(target_info))
.max()
.unwrap_or(0),
@ -1028,44 +1026,44 @@ impl<'a> Layout<'a> {
.flat_map(|layouts| {
layouts
.iter()
.map(|layout| layout.alignment_bytes(pointer_size))
.map(|layout| layout.alignment_bytes(target_info))
})
.max();
let tag_id_builtin = variant.tag_id_builtin();
match max_alignment {
Some(align) => round_up_to_alignment(
align.max(tag_id_builtin.alignment_bytes(pointer_size)),
tag_id_builtin.alignment_bytes(pointer_size),
align.max(tag_id_builtin.alignment_bytes(target_info)),
tag_id_builtin.alignment_bytes(target_info),
),
None => {
// none of the tags had any payload, but the tag id still contains information
tag_id_builtin.alignment_bytes(pointer_size)
tag_id_builtin.alignment_bytes(target_info)
}
}
}
Recursive(_)
| NullableWrapped { .. }
| NullableUnwrapped { .. }
| NonNullableUnwrapped(_) => pointer_size,
| NonNullableUnwrapped(_) => target_info.ptr_width() as u32,
}
}
Layout::LambdaSet(lambda_set) => lambda_set
.runtime_representation()
.alignment_bytes(pointer_size),
Layout::Builtin(builtin) => builtin.alignment_bytes(pointer_size),
Layout::RecursivePointer => pointer_size,
.alignment_bytes(target_info),
Layout::Builtin(builtin) => builtin.alignment_bytes(target_info),
Layout::RecursivePointer => target_info.ptr_width() as u32,
}
}
pub fn allocation_alignment_bytes(&self, pointer_size: u32) -> u32 {
pub fn allocation_alignment_bytes(&self, target_info: TargetInfo) -> u32 {
match self {
Layout::Builtin(builtin) => builtin.allocation_alignment_bytes(pointer_size),
Layout::Builtin(builtin) => builtin.allocation_alignment_bytes(target_info),
Layout::Struct(_) => unreachable!("not heap-allocated"),
Layout::Union(union_layout) => union_layout.allocation_alignment_bytes(pointer_size),
Layout::Union(union_layout) => union_layout.allocation_alignment_bytes(target_info),
Layout::LambdaSet(lambda_set) => lambda_set
.runtime_representation()
.allocation_alignment_bytes(pointer_size),
.allocation_alignment_bytes(target_info),
Layout::RecursivePointer => unreachable!("should be looked up to get an actual layout"),
}
}
@ -1149,7 +1147,7 @@ impl<'a> Layout<'a> {
/// But if we're careful when to invalidate certain keys, we still get some benefit
#[derive(Debug)]
pub struct LayoutCache<'a> {
ptr_bytes: u32,
target_info: TargetInfo,
_marker: std::marker::PhantomData<&'a u8>,
}
@ -1161,9 +1159,9 @@ pub enum CachedLayout<'a> {
}
impl<'a> LayoutCache<'a> {
pub fn new(ptr_bytes: u32) -> Self {
pub fn new(target_info: TargetInfo) -> Self {
Self {
ptr_bytes,
target_info,
_marker: Default::default(),
}
}
@ -1181,7 +1179,7 @@ impl<'a> LayoutCache<'a> {
arena,
subs,
seen: Vec::new_in(arena),
ptr_bytes: self.ptr_bytes,
target_info: self.target_info,
};
Layout::from_var(&mut env, var)
@ -1200,7 +1198,7 @@ impl<'a> LayoutCache<'a> {
arena,
subs,
seen: Vec::new_in(arena),
ptr_bytes: self.ptr_bytes,
target_info: self.target_info,
};
RawFunctionLayout::from_var(&mut env, var)
}
@ -1232,11 +1230,17 @@ impl<'a> Layout<'a> {
Layout::Builtin(Builtin::Float(FloatWidth::F32))
}
pub fn usize(ptr_bytes: u32) -> Layout<'a> {
match ptr_bytes {
4 => Self::u32(),
8 => Self::u64(),
_ => panic!("width of usize {} not supported", ptr_bytes),
pub fn usize(target_info: TargetInfo) -> Layout<'a> {
match target_info.ptr_width() {
roc_target::PtrWidth::Bytes4 => Self::u32(),
roc_target::PtrWidth::Bytes8 => Self::u64(),
}
}
pub fn isize(target_info: TargetInfo) -> Layout<'a> {
match target_info.ptr_width() {
roc_target::PtrWidth::Bytes4 => Self::i32(),
roc_target::PtrWidth::Bytes8 => Self::i64(),
}
}
@ -1310,42 +1314,46 @@ impl<'a> Builtin<'a> {
pub const WRAPPER_PTR: u32 = 0;
pub const WRAPPER_LEN: u32 = 1;
pub fn stack_size(&self, pointer_size: u32) -> u32 {
pub fn stack_size(&self, target_info: TargetInfo) -> u32 {
use Builtin::*;
let ptr_width = target_info.ptr_width() as u32;
match self {
Int(int) => int.stack_size(),
Float(float) => float.stack_size(),
Bool => Builtin::I1_SIZE,
Decimal => Builtin::DECIMAL_SIZE,
Str => Builtin::STR_WORDS * pointer_size,
Dict(_, _) => Builtin::DICT_WORDS * pointer_size,
Set(_) => Builtin::SET_WORDS * pointer_size,
List(_) => Builtin::LIST_WORDS * pointer_size,
Str => Builtin::STR_WORDS * ptr_width,
Dict(_, _) => Builtin::DICT_WORDS * ptr_width,
Set(_) => Builtin::SET_WORDS * ptr_width,
List(_) => Builtin::LIST_WORDS * ptr_width,
}
}
pub fn alignment_bytes(&self, pointer_size: u32) -> u32 {
pub fn alignment_bytes(&self, target_info: TargetInfo) -> u32 {
use std::mem::align_of;
use Builtin::*;
let ptr_width = target_info.ptr_width() as u32;
// for our data structures, what counts is the alignment of the `( ptr, len )` tuple, and
// since both of those are one pointer size, the alignment of that structure is a pointer
// size
match self {
Int(int_width) => int_width.alignment_bytes(),
Float(float_width) => float_width.alignment_bytes(),
Int(int_width) => int_width.alignment_bytes(target_info),
Float(float_width) => float_width.alignment_bytes(target_info),
Bool => align_of::<bool>() as u32,
Decimal => align_of::<i128>() as u32,
Dict(_, _) => pointer_size,
Set(_) => pointer_size,
Decimal => IntWidth::I128.alignment_bytes(target_info),
Dict(_, _) => ptr_width,
Set(_) => ptr_width,
// we often treat these as i128 (64-bit systems)
// or i64 (32-bit systems).
//
// In webassembly, For that to be safe
// they must be aligned to allow such access
List(_) => pointer_size,
Str => pointer_size,
List(_) => ptr_width,
Str => ptr_width,
}
}
@ -1425,21 +1433,23 @@ impl<'a> Builtin<'a> {
}
}
pub fn allocation_alignment_bytes(&self, pointer_size: u32) -> u32 {
pub fn allocation_alignment_bytes(&self, target_info: TargetInfo) -> u32 {
let ptr_width = target_info.ptr_width() as u32;
let allocation = match self {
Builtin::Int(_) | Builtin::Float(_) | Builtin::Bool | Builtin::Decimal => {
unreachable!("not heap-allocated")
}
Builtin::Str => pointer_size,
Builtin::Str => ptr_width,
Builtin::Dict(k, v) => k
.alignment_bytes(pointer_size)
.max(v.alignment_bytes(pointer_size))
.max(pointer_size),
Builtin::Set(k) => k.alignment_bytes(pointer_size).max(pointer_size),
Builtin::List(e) => e.alignment_bytes(pointer_size).max(pointer_size),
.alignment_bytes(target_info)
.max(v.alignment_bytes(target_info))
.max(ptr_width),
Builtin::Set(k) => k.alignment_bytes(target_info).max(ptr_width),
Builtin::List(e) => e.alignment_bytes(target_info).max(ptr_width),
};
allocation.max(pointer_size)
allocation.max(ptr_width)
}
}
@ -1451,7 +1461,7 @@ fn layout_from_flat_type<'a>(
let arena = env.arena;
let subs = env.subs;
let ptr_bytes = env.ptr_bytes;
let target_info = env.target_info;
match flat_type {
Apply(symbol, args) => {
@ -1461,7 +1471,7 @@ fn layout_from_flat_type<'a>(
// Ints
Symbol::NUM_NAT => {
debug_assert_eq!(args.len(), 0);
Ok(Layout::usize(env.ptr_bytes))
Ok(Layout::usize(env.target_info))
}
Symbol::NUM_I128 => {
@ -1527,7 +1537,7 @@ fn layout_from_flat_type<'a>(
let var = args[0];
let content = subs.get_content_without_compacting(var);
layout_from_num_content(content)
layout_from_num_content(content, target_info)
}
Symbol::STR_STR => Ok(Layout::Builtin(Builtin::Str)),
@ -1543,7 +1553,8 @@ fn layout_from_flat_type<'a>(
}
}
Func(_, closure_var, _) => {
let lambda_set = LambdaSet::from_var(env.arena, env.subs, closure_var, env.ptr_bytes)?;
let lambda_set =
LambdaSet::from_var(env.arena, env.subs, closure_var, env.target_info)?;
Ok(Layout::LambdaSet(lambda_set))
}
@ -1563,8 +1574,8 @@ fn layout_from_flat_type<'a>(
}
pairs.sort_by(|(label1, layout1), (label2, layout2)| {
let size1 = layout1.alignment_bytes(ptr_bytes);
let size2 = layout2.alignment_bytes(ptr_bytes);
let size1 = layout1.alignment_bytes(target_info);
let size2 = layout2.alignment_bytes(target_info);
size2.cmp(&size1).then(label1.cmp(label2))
});
@ -1584,7 +1595,7 @@ fn layout_from_flat_type<'a>(
debug_assert!(ext_var_is_empty_tag_union(subs, ext_var));
Ok(layout_from_tag_union(arena, &tags, subs, env.ptr_bytes))
Ok(layout_from_tag_union(arena, &tags, subs, env.target_info))
}
FunctionOrTagUnion(tag_name, _, ext_var) => {
debug_assert!(
@ -1595,7 +1606,7 @@ fn layout_from_flat_type<'a>(
let union_tags = UnionTags::from_tag_name_index(tag_name);
let (tags, _) = union_tags.unsorted_tags_and_ext(subs, ext_var);
Ok(layout_from_tag_union(arena, &tags, subs, env.ptr_bytes))
Ok(layout_from_tag_union(arena, &tags, subs, env.target_info))
}
RecursiveTagUnion(rec_var, tags, ext_var) => {
let (tags, ext_var) = tags.unsorted_tags_and_ext(subs, ext_var);
@ -1645,8 +1656,8 @@ fn layout_from_flat_type<'a>(
}
tag_layout.sort_by(|layout1, layout2| {
let size1 = layout1.alignment_bytes(ptr_bytes);
let size2 = layout2.alignment_bytes(ptr_bytes);
let size1 = layout1.alignment_bytes(target_info);
let size2 = layout2.alignment_bytes(target_info);
size2.cmp(&size1)
});
@ -1691,13 +1702,13 @@ pub fn sort_record_fields<'a>(
arena: &'a Bump,
var: Variable,
subs: &Subs,
ptr_bytes: u32,
target_info: TargetInfo,
) -> Result<Vec<'a, SortedField<'a>>, LayoutProblem> {
let mut env = Env {
arena,
subs,
seen: Vec::new_in(arena),
ptr_bytes,
target_info,
};
let (it, _) = match gather_fields_unsorted_iter(subs, RecordFields::empty(), var) {
@ -1716,7 +1727,7 @@ fn sort_record_fields_help<'a>(
env: &mut Env<'a, '_>,
fields_map: impl Iterator<Item = (Lowercase, RecordField<Variable>)>,
) -> Result<Vec<'a, SortedField<'a>>, LayoutProblem> {
let ptr_bytes = env.ptr_bytes;
let target_info = env.target_info;
// Sort the fields by label
let mut sorted_fields = Vec::with_capacity_in(fields_map.size_hint().0, env.arena);
@ -1738,8 +1749,8 @@ fn sort_record_fields_help<'a>(
|(label1, _, res_layout1), (label2, _, res_layout2)| match res_layout1 {
Ok(layout1) | Err(layout1) => match res_layout2 {
Ok(layout2) | Err(layout2) => {
let size1 = layout1.alignment_bytes(ptr_bytes);
let size2 = layout2.alignment_bytes(ptr_bytes);
let size1 = layout1.alignment_bytes(target_info);
let size2 = layout2.alignment_bytes(target_info);
size2.cmp(&size1).then(label1.cmp(label2))
}
@ -1873,7 +1884,7 @@ pub fn union_sorted_tags<'a>(
arena: &'a Bump,
var: Variable,
subs: &Subs,
ptr_bytes: u32,
target_info: TargetInfo,
) -> Result<UnionVariant<'a>, LayoutProblem> {
let var =
if let Content::RecursionVar { structure, .. } = subs.get_content_without_compacting(var) {
@ -1886,7 +1897,7 @@ pub fn union_sorted_tags<'a>(
let result = match roc_types::pretty_print::chase_ext_tag_union(subs, var, &mut tags_vec) {
Ok(()) | Err((_, Content::FlexVar(_))) | Err((_, Content::RecursionVar { .. })) => {
let opt_rec_var = get_recursion_var(subs, var);
union_sorted_tags_help(arena, tags_vec, opt_rec_var, subs, ptr_bytes)
union_sorted_tags_help(arena, tags_vec, opt_rec_var, subs, target_info)
}
Err((_, Content::Error)) => return Err(LayoutProblem::Erroneous),
Err(other) => panic!("invalid content in tag union variable: {:?}", other),
@ -1920,7 +1931,7 @@ fn union_sorted_tags_help_new<'a>(
tags_list: &[(&'_ TagName, &[Variable])],
opt_rec_var: Option<Variable>,
subs: &Subs,
ptr_bytes: u32,
target_info: TargetInfo,
) -> UnionVariant<'a> {
// sort up front; make sure the ordering stays intact!
let mut tags_list = Vec::from_iter_in(tags_list.iter(), arena);
@ -1930,7 +1941,7 @@ fn union_sorted_tags_help_new<'a>(
arena,
subs,
seen: Vec::new_in(arena),
ptr_bytes,
target_info,
};
match tags_list.len() {
@ -1949,7 +1960,8 @@ fn union_sorted_tags_help_new<'a>(
match tag_name {
TagName::Private(Symbol::NUM_AT_NUM) => {
let var = arguments[0];
layouts.push(unwrap_num_tag(subs, var, ptr_bytes).expect("invalid num layout"));
layouts
.push(unwrap_num_tag(subs, var, target_info).expect("invalid num layout"));
}
_ => {
for &var in arguments {
@ -1973,8 +1985,8 @@ fn union_sorted_tags_help_new<'a>(
}
layouts.sort_by(|layout1, layout2| {
let size1 = layout1.alignment_bytes(ptr_bytes);
let size2 = layout2.alignment_bytes(ptr_bytes);
let size1 = layout1.alignment_bytes(target_info);
let size2 = layout2.alignment_bytes(target_info);
size2.cmp(&size1)
});
@ -2051,8 +2063,8 @@ fn union_sorted_tags_help_new<'a>(
}
arg_layouts.sort_by(|layout1, layout2| {
let size1 = layout1.alignment_bytes(ptr_bytes);
let size2 = layout2.alignment_bytes(ptr_bytes);
let size1 = layout1.alignment_bytes(target_info);
let size2 = layout2.alignment_bytes(target_info);
size2.cmp(&size1)
});
@ -2123,7 +2135,7 @@ pub fn union_sorted_tags_help<'a>(
mut tags_vec: std::vec::Vec<(TagName, std::vec::Vec<Variable>)>,
opt_rec_var: Option<Variable>,
subs: &Subs,
ptr_bytes: u32,
target_info: TargetInfo,
) -> UnionVariant<'a> {
// sort up front; make sure the ordering stays intact!
tags_vec.sort_unstable_by(|(a, _), (b, _)| a.cmp(b));
@ -2132,7 +2144,7 @@ pub fn union_sorted_tags_help<'a>(
arena,
subs,
seen: Vec::new_in(arena),
ptr_bytes,
target_info,
};
match tags_vec.len() {
@ -2151,7 +2163,8 @@ pub fn union_sorted_tags_help<'a>(
match tag_name {
TagName::Private(Symbol::NUM_AT_NUM) => {
layouts.push(
unwrap_num_tag(subs, arguments[0], ptr_bytes).expect("invalid num layout"),
unwrap_num_tag(subs, arguments[0], target_info)
.expect("invalid num layout"),
);
}
_ => {
@ -2181,8 +2194,8 @@ pub fn union_sorted_tags_help<'a>(
}
layouts.sort_by(|layout1, layout2| {
let size1 = layout1.alignment_bytes(ptr_bytes);
let size2 = layout2.alignment_bytes(ptr_bytes);
let size1 = layout1.alignment_bytes(target_info);
let size2 = layout2.alignment_bytes(target_info);
size2.cmp(&size1)
});
@ -2264,8 +2277,8 @@ pub fn union_sorted_tags_help<'a>(
}
arg_layouts.sort_by(|layout1, layout2| {
let size1 = layout1.alignment_bytes(ptr_bytes);
let size2 = layout2.alignment_bytes(ptr_bytes);
let size1 = layout1.alignment_bytes(target_info);
let size2 = layout2.alignment_bytes(target_info);
size2.cmp(&size1)
});
@ -2335,20 +2348,20 @@ fn layout_from_newtype<'a>(
arena: &'a Bump,
tags: &UnsortedUnionTags,
subs: &Subs,
ptr_bytes: u32,
target_info: TargetInfo,
) -> Layout<'a> {
debug_assert!(tags.is_newtype_wrapper(subs));
let (tag_name, var) = tags.get_newtype(subs);
if tag_name == &TagName::Private(Symbol::NUM_AT_NUM) {
unwrap_num_tag(subs, var, ptr_bytes).expect("invalid Num argument")
unwrap_num_tag(subs, var, target_info).expect("invalid Num argument")
} else {
let mut env = Env {
arena,
subs,
seen: Vec::new_in(arena),
ptr_bytes,
target_info,
};
match Layout::from_var(&mut env, var) {
@ -2372,12 +2385,12 @@ fn layout_from_tag_union<'a>(
arena: &'a Bump,
tags: &UnsortedUnionTags,
subs: &Subs,
ptr_bytes: u32,
target_info: TargetInfo,
) -> Layout<'a> {
use UnionVariant::*;
if tags.is_newtype_wrapper(subs) {
return layout_from_newtype(arena, tags, subs, ptr_bytes);
return layout_from_newtype(arena, tags, subs, target_info);
}
let tags_vec = &tags.tags;
@ -2388,11 +2401,12 @@ fn layout_from_tag_union<'a>(
let &var = arguments.iter().next().unwrap();
unwrap_num_tag(subs, var, ptr_bytes).expect("invalid Num argument")
unwrap_num_tag(subs, var, target_info).expect("invalid Num argument")
}
_ => {
let opt_rec_var = None;
let variant = union_sorted_tags_help_new(arena, tags_vec, opt_rec_var, subs, ptr_bytes);
let variant =
union_sorted_tags_help_new(arena, tags_vec, opt_rec_var, subs, target_info);
match variant {
Never => Layout::VOID,
@ -2490,12 +2504,13 @@ pub fn ext_var_is_empty_tag_union(_: &Subs, _: Variable) -> bool {
unreachable!();
}
fn layout_from_num_content<'a>(content: &Content) -> Result<Layout<'a>, LayoutProblem> {
fn layout_from_num_content<'a>(
content: &Content,
target_info: TargetInfo,
) -> Result<Layout<'a>, LayoutProblem> {
use roc_types::subs::Content::*;
use roc_types::subs::FlatType::*;
let ptr_bytes = 8;
match content {
RecursionVar { .. } => panic!("recursion var in num"),
FlexVar(_) | RigidVar(_) => {
@ -2507,7 +2522,7 @@ fn layout_from_num_content<'a>(content: &Content) -> Result<Layout<'a>, LayoutPr
}
Structure(Apply(symbol, args)) => match *symbol {
// Ints
Symbol::NUM_NAT => Ok(Layout::usize(ptr_bytes)),
Symbol::NUM_NAT => Ok(Layout::usize(target_info)),
Symbol::NUM_INTEGER => Ok(Layout::i64()),
Symbol::NUM_I128 => Ok(Layout::i128()),
@ -2550,7 +2565,7 @@ fn layout_from_num_content<'a>(content: &Content) -> Result<Layout<'a>, LayoutPr
fn unwrap_num_tag<'a>(
subs: &Subs,
var: Variable,
ptr_bytes: u32,
target_info: TargetInfo,
) -> Result<Layout<'a>, LayoutProblem> {
match subs.get_content_without_compacting(var) {
Content::Alias(Symbol::NUM_INTEGER, args, _) => {
@ -2575,7 +2590,7 @@ fn unwrap_num_tag<'a>(
Symbol::NUM_UNSIGNED32 => Layout::u32(),
Symbol::NUM_UNSIGNED16 => Layout::u16(),
Symbol::NUM_UNSIGNED8 => Layout::u8(),
Symbol::NUM_NATURAL => Layout::usize(ptr_bytes),
Symbol::NUM_NATURAL => Layout::usize(target_info),
_ => unreachable!("not a valid int variant: {:?} {:?}", symbol, args),
};
@ -2821,8 +2836,8 @@ mod test {
let layout = Layout::Union(UnionLayout::NonRecursive(&tt));
let ptr_width = 8;
assert_eq!(layout.stack_size(ptr_width), 1);
assert_eq!(layout.alignment_bytes(ptr_width), 1);
let target_info = TargetInfo::default_x86_64();
assert_eq!(layout.stack_size(target_info), 1);
assert_eq!(layout.alignment_bytes(target_info), 1);
}
}

View File

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

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_parse = { path = "../parse" }
roc_solve = { path = "../solve" }
roc_target = { path = "../roc_target" }
pretty_assertions = "1.0.0"
indoc = "1.0.3"
tempfile = "3.2.0"

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -25,6 +25,8 @@ use roc_mono::ir::Proc;
use roc_mono::ir::ProcLayout;
const TARGET_INFO: roc_target::TargetInfo = roc_target::TargetInfo::default_x86_64();
/// Without this, some tests pass in `cargo test --release` but fail without
/// the --release flag because they run out of stack space. This increases
/// stack size for debug builds only, while leaving the stack space at the default
@ -104,7 +106,7 @@ fn compiles_to_ir(test_name: &str, src: &str) {
&stdlib,
src_dir,
exposed_types,
8,
TARGET_INFO,
builtin_defs_map,
);

View File

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

View File

@ -428,7 +428,7 @@ pub fn load_modules_for_files(filenames: Vec<PathBuf>, std_lib: StdLib) -> Vec<L
&std_lib,
src_dir.as_path(),
MutMap::default(),
std::mem::size_of::<usize>() as u32, // This is just type-checking for docs, so "target" doesn't matter
roc_target::TargetInfo::default_x86_64(), // This is just type-checking for docs, so "target" doesn't matter
builtin_defs_map,
) {
Ok(loaded) => modules.push(loaded),

View File

@ -21,6 +21,22 @@ main =
|> Task.map (\_ -> {})
nest : (I64, Expr -> IO Expr), I64, Expr -> IO Expr
nest = \f, n, e -> Task.loop { s: n, f, m: n, x: e } nestHelp
State : { s : I64, f : I64, Expr -> IO Expr, m : I64, x : Expr }
nestHelp : State -> IO [ Step State, Done Expr ]
nestHelp = \{ s, f, m, x } ->
when m is
0 ->
Task.succeed (Done x)
_ ->
w <- Task.after (f (s - m) x)
Task.succeed (Step { s, f, m: (m - 1), x: w })
Expr : [ Val I64, Var Str, Add Expr Expr, Mul Expr Expr, Pow Expr Expr, Ln Expr ]
divmod : I64, I64 -> Result { div : I64, mod : I64 } [ DivByZero ]*
@ -180,18 +196,6 @@ count = \expr ->
Ln f ->
count f
nest : (I64, Expr -> IO Expr), I64, Expr -> IO Expr
nest = \f, n, e -> nestHelp n f n e
nestHelp : I64, (I64, Expr -> IO Expr), I64, Expr -> IO Expr
nestHelp = \s, f, m, x ->
when m is
0 ->
Task.succeed x
_ ->
f (s - m) x |> Task.after \w -> nestHelp s f (m - 1) w
deriv : I64, Expr -> IO Expr
deriv = \i, f ->
fprime = d "x" f

View File

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

View File

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

View File

@ -1,9 +1,27 @@
interface Task
exposes [ Task, succeed, fail, await, map, onFail, attempt, fromResult ]
exposes [ Task, succeed, fail, await, map, onFail, attempt, fromResult, loop ]
imports [ fx.Effect ]
Task ok err : Effect.Effect (Result ok err)
loop : state, (state -> Task [ Step state, Done done ] err) -> Task done err
loop = \state, step ->
looper = \current ->
step current
|> Effect.map
\res ->
when res is
Ok (Step newState) ->
Step newState
Ok (Done result) ->
Done (Ok result)
Err e ->
Done (Err e)
Effect.loop state looper
succeed : val -> Task val *
succeed = \val ->
Effect.always (Ok val)

View File

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

View File

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