working mono

This commit is contained in:
Folkert 2021-11-20 23:25:30 +01:00
parent 25a64f4a57
commit c4ec9aa898
15 changed files with 431 additions and 358 deletions

1
Cargo.lock generated
View file

@ -3458,6 +3458,7 @@ dependencies = [
"bumpalo",
"hashbrown 0.11.2",
"morphic_lib",
"roc_builtins",
"roc_can",
"roc_collections",
"roc_module",

View file

@ -71,7 +71,7 @@ fn jit_to_ast_help<'a>(
content: &Content,
) -> Result<Expr<'a>, ToAstProblem> {
match layout {
Layout::Builtin(Builtin::Int1) => Ok(run_jit_function!(lib, main_fn_name, bool, |num| {
Layout::Builtin(Builtin::Bool) => Ok(run_jit_function!(lib, main_fn_name, bool, |num| {
bool_to_ast(env, num, content)
})),
Layout::Builtin(Builtin::Int8) => {
@ -248,7 +248,7 @@ fn jit_to_ast_help<'a>(
.unwrap_or(0);
let tag_id = match union_layout.tag_id_builtin() {
Builtin::Int1 => {
Builtin::Bool => {
*(ptr.add(offset as usize) as *const i8) as i64
}
Builtin::Int8 => {
@ -406,7 +406,7 @@ fn ptr_to_ast<'a>(
num_to_ast(env, number_literal_to_ast(env.arena, num), content)
}
Layout::Builtin(Builtin::Int1) => {
Layout::Builtin(Builtin::Bool) => {
// TODO: bits are not as expected here.
// num is always false at the moment.
let num = unsafe { *(ptr as *const bool) };

View file

@ -1,3 +1,4 @@
use roc_module::symbol::Symbol;
use std::ops::Index;
pub const BUILTINS_HOST_OBJ_PATH: &str = env!(
@ -27,13 +28,55 @@ pub enum DecWidth {
}
#[repr(u8)]
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub enum FloatWidth {
F32,
F64,
F128,
}
impl FloatWidth {
pub const fn stack_size(&self) -> u32 {
use FloatWidth::*;
match self {
F32 => 4,
F64 => 8,
F128 => 16,
}
}
pub const fn alignment_bytes(&self) -> u32 {
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,
F128 => align_of::<i128>() as u32,
}
}
pub const fn try_from_symbol(symbol: Symbol) -> Option<Self> {
match symbol {
Symbol::NUM_FLOAT => Some(FloatWidth::F64),
Symbol::NUM_F64 | Symbol::NUM_BINARY64 | Symbol::NUM_AT_BINARY64 => {
Some(FloatWidth::F64)
}
Symbol::NUM_F32 | Symbol::NUM_BINARY32 | Symbol::NUM_AT_BINARY32 => {
Some(FloatWidth::F32)
}
_ => None,
}
}
}
#[repr(u8)]
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub enum IntWidth {
U8,
U16,
@ -47,6 +90,61 @@ pub enum IntWidth {
I128,
}
impl IntWidth {
pub const fn stack_size(&self) -> u32 {
use IntWidth::*;
match self {
U8 | I8 => 1,
U16 | I16 => 2,
U32 | I32 => 4,
U64 | I64 => 8,
U128 | I128 => 16,
}
}
pub const fn alignment_bytes(&self) -> u32 {
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,
U128 | I128 => align_of::<i128>() as u32,
}
}
pub const fn try_from_symbol(symbol: Symbol) -> Option<Self> {
match symbol {
Symbol::NUM_INT => Some(IntWidth::I64),
Symbol::NUM_I128 | Symbol::NUM_SIGNED128 | Symbol::NUM_AT_SIGNED128 => {
Some(IntWidth::I128)
}
Symbol::NUM_I64 | Symbol::NUM_SIGNED64 | Symbol::NUM_AT_SIGNED64 => Some(IntWidth::I64),
Symbol::NUM_I32 | Symbol::NUM_SIGNED32 | Symbol::NUM_AT_SIGNED32 => Some(IntWidth::I32),
Symbol::NUM_I16 | Symbol::NUM_SIGNED16 | Symbol::NUM_AT_SIGNED16 => Some(IntWidth::I16),
Symbol::NUM_I8 | Symbol::NUM_SIGNED8 | Symbol::NUM_AT_SIGNED8 => Some(IntWidth::I8),
Symbol::NUM_U128 | Symbol::NUM_UNSIGNED128 | Symbol::NUM_AT_UNSIGNED128 => {
Some(IntWidth::U128)
}
Symbol::NUM_U64 | Symbol::NUM_UNSIGNED64 | Symbol::NUM_AT_UNSIGNED64 => {
Some(IntWidth::U64)
}
Symbol::NUM_U32 | Symbol::NUM_UNSIGNED32 | Symbol::NUM_AT_UNSIGNED32 => {
Some(IntWidth::U32)
}
Symbol::NUM_U16 | Symbol::NUM_UNSIGNED16 | Symbol::NUM_AT_UNSIGNED16 => {
Some(IntWidth::U16)
}
Symbol::NUM_U8 | Symbol::NUM_UNSIGNED8 | Symbol::NUM_AT_UNSIGNED8 => Some(IntWidth::U8),
_ => None,
}
}
}
impl Index<DecWidth> for IntrinsicName {
type Output = str;

View file

@ -410,7 +410,7 @@ where
"Eq: expected all arguments of to have the same layout"
);
debug_assert_eq!(
Layout::Builtin(Builtin::Int1),
Layout::Builtin(Builtin::Bool),
*ret_layout,
"Eq: expected to have return layout of type I1"
);
@ -427,7 +427,7 @@ where
"NotEq: expected all arguments of to have the same layout"
);
debug_assert_eq!(
Layout::Builtin(Builtin::Int1),
Layout::Builtin(Builtin::Bool),
*ret_layout,
"NotEq: expected to have return layout of type I1"
);

View file

@ -715,7 +715,7 @@ pub fn int_with_precision<'a, 'ctx, 'env>(
Builtin::Int32 => env.context.i32_type().const_int(value as u64, false),
Builtin::Int16 => env.context.i16_type().const_int(value as u64, false),
Builtin::Int8 => env.context.i8_type().const_int(value as u64, false),
Builtin::Int1 => env.context.bool_type().const_int(value as u64, false),
Builtin::Bool => env.context.bool_type().const_int(value as u64, false),
_ => panic!("Invalid layout for int literal = {:?}", precision),
}
}
@ -3072,7 +3072,7 @@ fn build_switch_ir<'a, 'ctx, 'env>(
// Build the cases
let mut incoming = Vec::with_capacity_in(branches.len(), arena);
if let Layout::Builtin(Builtin::Int1) = cond_layout {
if let Layout::Builtin(Builtin::Bool) = cond_layout {
match (branches, default_branch) {
([(0, _, false_branch)], true_branch) | ([(1, _, true_branch)], false_branch) => {
let then_block = context.append_basic_block(parent, "then_block");
@ -5133,7 +5133,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
closure_layout,
function_owns_closure_data,
argument_layouts,
Layout::Builtin(Builtin::Int1),
Layout::Builtin(Builtin::Bool),
);
list_any(env, roc_function_call, list, element_layout)
@ -5160,7 +5160,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
closure_layout,
function_owns_closure_data,
argument_layouts,
Layout::Builtin(Builtin::Int1),
Layout::Builtin(Builtin::Bool),
);
list_all(env, roc_function_call, list, element_layout)
@ -5193,7 +5193,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
closure_layout,
function_owns_closure_data,
argument_layouts,
Layout::Builtin(Builtin::Int1),
Layout::Builtin(Builtin::Bool),
);
list_find_unsafe(env, layout_ids, roc_function_call, list, element_layout)
}
@ -6101,7 +6101,7 @@ fn to_cc_type_builtin<'a, 'ctx, 'env>(
| Builtin::Int32
| Builtin::Int16
| Builtin::Int8
| Builtin::Int1
| Builtin::Bool
| Builtin::Usize
| Builtin::Decimal
| Builtin::Float128

View file

@ -128,7 +128,7 @@ fn hash_builtin<'a, 'ctx, 'env>(
| Builtin::Int32
| Builtin::Int16
| Builtin::Int8
| Builtin::Int1
| Builtin::Bool
| Builtin::Float64
| Builtin::Float32
| Builtin::Float128

View file

@ -93,7 +93,7 @@ fn build_eq_builtin<'a, 'ctx, 'env>(
Builtin::Int32 => int_cmp(IntPredicate::EQ, "eq_i32"),
Builtin::Int16 => int_cmp(IntPredicate::EQ, "eq_i16"),
Builtin::Int8 => int_cmp(IntPredicate::EQ, "eq_i8"),
Builtin::Int1 => int_cmp(IntPredicate::EQ, "eq_i1"),
Builtin::Bool => int_cmp(IntPredicate::EQ, "eq_i1"),
Builtin::Usize => int_cmp(IntPredicate::EQ, "eq_usize"),
@ -236,7 +236,7 @@ fn build_neq_builtin<'a, 'ctx, 'env>(
Builtin::Int32 => int_cmp(IntPredicate::NE, "neq_i32"),
Builtin::Int16 => int_cmp(IntPredicate::NE, "neq_i16"),
Builtin::Int8 => int_cmp(IntPredicate::NE, "neq_i8"),
Builtin::Int1 => int_cmp(IntPredicate::NE, "neq_i1"),
Builtin::Bool => int_cmp(IntPredicate::NE, "neq_i1"),
Builtin::Usize => int_cmp(IntPredicate::NE, "neq_usize"),

View file

@ -151,7 +151,7 @@ pub fn basic_type_from_builtin<'a, 'ctx, 'env>(
Int32 => context.i32_type().as_basic_type_enum(),
Int16 => context.i16_type().as_basic_type_enum(),
Int8 => context.i8_type().as_basic_type_enum(),
Int1 => context.bool_type().as_basic_type_enum(),
Bool => context.bool_type().as_basic_type_enum(),
Usize => ptr_int(context, ptr_bytes).as_basic_type_enum(),
Decimal => context.i128_type().as_basic_type_enum(),
Float128 => context.f128_type().as_basic_type_enum(),

View file

@ -328,7 +328,7 @@ impl<'a> WasmBackend<'a> {
self.start_block(BlockType::NoResult)
}
let is_bool = matches!(cond_layout, Layout::Builtin(Builtin::Int1));
let is_bool = matches!(cond_layout, Layout::Builtin(Builtin::Bool));
let cond_type = WasmLayout::new(cond_layout).value_type();
// then, we jump whenever the value under scrutiny is equal to the value of a branch

View file

@ -26,7 +26,7 @@ impl WasmLayout {
let alignment_bytes = layout.alignment_bytes(PTR_SIZE);
match layout {
Layout::Builtin(Int32 | Int16 | Int8 | Int1 | Usize) => Self::Primitive(I32, size),
Layout::Builtin(Int32 | Int16 | Int8 | Bool | Usize) => Self::Primitive(I32, size),
Layout::Builtin(Int64) => Self::Primitive(I64, size),

View file

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

View file

@ -590,7 +590,7 @@ impl<'a> ResultRepr<'a> {
err: tags[ERR_TAG_ID as usize][0],
ok: tags[OK_TAG_ID as usize][0],
},
Layout::Builtin(Builtin::Int1) => ResultRepr::Int1,
Layout::Builtin(Builtin::Bool) => ResultRepr::Int1,
other => unreachable!("unexpected layout: {:?}", other),
}
}
@ -1086,7 +1086,7 @@ fn call_spec(
Ok(new_state)
};
let state_layout = Layout::Builtin(Builtin::Int1);
let state_layout = Layout::Builtin(Builtin::Bool);
let state_type = layout_spec(builder, &state_layout)?;
let init_state = new_num(builder, block)?;
@ -1105,7 +1105,7 @@ fn call_spec(
Ok(new_state)
};
let state_layout = Layout::Builtin(Builtin::Int1);
let state_layout = Layout::Builtin(Builtin::Bool);
let state_type = layout_spec(builder, &state_layout)?;
let init_state = new_num(builder, block)?;
@ -1116,7 +1116,7 @@ fn call_spec(
let list = env.symbols[xs];
// ListFindUnsafe returns { value: v, found: Bool=Int1 }
let output_layouts = vec![arg_layouts[0], Layout::Builtin(Builtin::Int1)];
let output_layouts = vec![arg_layouts[0], Layout::Builtin(Builtin::Bool)];
let output_layout = Layout::Struct(&output_layouts);
let output_type = layout_spec(builder, &output_layout)?;
@ -1718,8 +1718,8 @@ fn builtin_spec(
use Builtin::*;
match builtin {
Int128 | Int64 | Int32 | Int16 | Int8 | Int1 | Usize => builder.add_tuple_type(&[]),
Decimal | Float128 | Float64 | Float32 => builder.add_tuple_type(&[]),
Int(_) | Usize | Bool => builder.add_tuple_type(&[]),
Decimal | Float(_) => builder.add_tuple_type(&[]),
Str | EmptyStr => str_type(builder),
Dict(key_layout, value_layout) => {
let value_type = layout_spec_help(builder, value_layout, when_recursive)?;

View file

@ -1,9 +1,9 @@
use crate::exhaustive::{Ctor, RenderAs, TagId, Union};
use crate::ir::{
BranchInfo, DestructType, Env, Expr, FloatPrecision, IntPrecision, JoinPointId, Literal, Param,
Pattern, Procs, Stmt,
BranchInfo, DestructType, Env, Expr, JoinPointId, Literal, Param, Pattern, Procs, Stmt,
};
use crate::layout::{Builtin, Layout, LayoutCache, TagIdIntType, UnionLayout};
use roc_builtins::bitcode::{FloatWidth, IntWidth};
use roc_collections::all::{MutMap, MutSet};
use roc_module::ident::TagName;
use roc_module::low_level::LowLevel;
@ -86,8 +86,8 @@ enum Test<'a> {
union: crate::exhaustive::Union,
arguments: Vec<(Pattern<'a>, Layout<'a>)>,
},
IsInt(i128, IntPrecision),
IsFloat(u64, FloatPrecision),
IsInt(i128, IntWidth),
IsFloat(u64, FloatWidth),
IsDecimal(RocDec),
IsStr(Box<str>),
IsBit(bool),
@ -1300,7 +1300,7 @@ fn test_to_equality<'a>(
debug_assert!(test_int <= i64::MAX as i128);
let lhs = Expr::Literal(Literal::Int(test_int as i128));
let lhs_symbol = env.unique_symbol();
stores.push((lhs_symbol, precision.as_layout(), lhs));
stores.push((lhs_symbol, Layout::int_width(precision), lhs));
(stores, lhs_symbol, rhs_symbol, None)
}
@ -1310,7 +1310,7 @@ fn test_to_equality<'a>(
let test_float = f64::from_bits(test_int as u64);
let lhs = Expr::Literal(Literal::Float(test_float));
let lhs_symbol = env.unique_symbol();
stores.push((lhs_symbol, precision.as_layout(), lhs));
stores.push((lhs_symbol, Layout::float_width(precision), lhs));
(stores, lhs_symbol, rhs_symbol, None)
}
@ -1330,7 +1330,7 @@ fn test_to_equality<'a>(
let lhs = Expr::Literal(Literal::Byte(test_byte as u8));
let lhs_symbol = env.unique_symbol();
stores.push((lhs_symbol, Layout::Builtin(Builtin::Int8), lhs));
stores.push((lhs_symbol, Layout::u8(), lhs));
(stores, lhs_symbol, rhs_symbol, None)
}
@ -1338,7 +1338,7 @@ fn test_to_equality<'a>(
Test::IsBit(test_bit) => {
let lhs = Expr::Literal(Literal::Bool(test_bit));
let lhs_symbol = env.unique_symbol();
stores.push((lhs_symbol, Layout::Builtin(Builtin::Int1), lhs));
stores.push((lhs_symbol, Layout::Builtin(Builtin::Bool), lhs));
(stores, lhs_symbol, rhs_symbol, None)
}
@ -1459,7 +1459,7 @@ fn compile_test_help<'a>(
cond = Stmt::Switch {
cond_symbol: test_symbol,
cond_layout: Layout::Builtin(Builtin::Int1),
cond_layout: Layout::Builtin(Builtin::Bool),
ret_layout,
branches,
default_branch,
@ -1478,7 +1478,7 @@ fn compile_test_help<'a>(
cond = Stmt::Let(
test_symbol,
test,
Layout::Builtin(Builtin::Int1),
Layout::Builtin(Builtin::Bool),
arena.alloc(cond),
);
@ -1622,7 +1622,7 @@ fn decide_to_branching<'a>(
let decide = crate::ir::cond(
env,
test_symbol,
Layout::Builtin(Builtin::Int1),
Layout::Builtin(Builtin::Bool),
pass_expr,
fail_expr,
ret_layout,
@ -1631,7 +1631,7 @@ fn decide_to_branching<'a>(
// calculate the guard value
let param = Param {
symbol: test_symbol,
layout: Layout::Builtin(Builtin::Int1),
layout: Layout::Builtin(Builtin::Bool),
borrow: false,
};

View file

@ -7,6 +7,7 @@ use crate::layout::{
};
use bumpalo::collections::Vec;
use bumpalo::Bump;
use roc_builtins::bitcode::{FloatWidth, IntWidth};
use roc_can::expr::ClosureData;
use roc_collections::all::{default_hasher, BumpMap, BumpMapDefault, MutMap};
use roc_module::ident::{ForeignSymbol, Lowercase, TagName};
@ -2424,11 +2425,11 @@ fn specialize_external<'a>(
}
ClosureRepresentation::Other(layout) => match layout {
Layout::Builtin(Builtin::Int1) => {
Layout::Builtin(Builtin::Bool) => {
// just ignore this value
// IDEA don't pass this value in the future
}
Layout::Builtin(Builtin::Int8) => {
Layout::Builtin(Builtin::Int(IntWidth::U8)) => {
// just ignore this value
// IDEA don't pass this value in the future
}
@ -2953,16 +2954,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) {
IntOrFloat::SignedIntType(_) | IntOrFloat::UnsignedIntType(_) => {
Some(Literal::Int(*int))
}
IntOrFloat::Int(_) | IntOrFloat::Natural => 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) {
IntOrFloat::BinaryFloatType(_) => Some(Literal::Float(*float)),
IntOrFloat::Float(_) => Some(Literal::Float(*float)),
IntOrFloat::DecimalFloatType => {
let dec = match RocDec::from_str(float_str) {
Some(d) => d,
@ -2980,10 +2979,8 @@ fn try_make_literal<'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) {
IntOrFloat::SignedIntType(_) | IntOrFloat::UnsignedIntType(_) => {
Some(Literal::Int((*num).into()))
}
IntOrFloat::BinaryFloatType(_) => Some(Literal::Float(*num as f64)),
IntOrFloat::Int(_) | IntOrFloat::Natural => Some(Literal::Int((*num).into())),
IntOrFloat::Float(_) => Some(Literal::Float(*num as f64)),
IntOrFloat::DecimalFloatType => {
let dec = match RocDec::from_str(num_str) {
Some(d) => d,
@ -3017,16 +3014,16 @@ 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) {
IntOrFloat::SignedIntType(precision) => Stmt::Let(
IntOrFloat::Int(precision) => Stmt::Let(
assigned,
Expr::Literal(Literal::Int(int)),
precision.as_layout(),
Layout::Builtin(Builtin::Int(precision)),
hole,
),
IntOrFloat::UnsignedIntType(precision) => Stmt::Let(
IntOrFloat::Natural => Stmt::Let(
assigned,
Expr::Literal(Literal::Int(int)),
precision.as_layout(),
Layout::usize(),
hole,
),
_ => unreachable!("unexpected float precision for integer"),
@ -3035,10 +3032,10 @@ pub fn with_hole<'a>(
Float(_, precision, float_str, float) => {
match num_argument_to_int_or_float(env.subs, env.ptr_bytes, precision, true) {
IntOrFloat::BinaryFloatType(precision) => Stmt::Let(
IntOrFloat::Float(precision) => Stmt::Let(
assigned,
Expr::Literal(Literal::Float(float)),
precision.as_layout(),
Layout::Builtin(Builtin::Float(precision)),
hole,
),
IntOrFloat::DecimalFloatType => {
@ -3067,22 +3064,22 @@ 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) {
IntOrFloat::SignedIntType(precision) => Stmt::Let(
IntOrFloat::Int(precision) => Stmt::Let(
assigned,
Expr::Literal(Literal::Int(num.into())),
precision.as_layout(),
Layout::int_width(precision),
hole,
),
IntOrFloat::UnsignedIntType(precision) => Stmt::Let(
IntOrFloat::Natural => Stmt::Let(
assigned,
Expr::Literal(Literal::Int(num.into())),
precision.as_layout(),
Layout::usize(),
hole,
),
IntOrFloat::BinaryFloatType(precision) => Stmt::Let(
IntOrFloat::Float(precision) => Stmt::Let(
assigned,
Expr::Literal(Literal::Float(num as f64)),
precision.as_layout(),
Layout::float_width(precision),
hole,
),
IntOrFloat::DecimalFloatType => {
@ -4467,7 +4464,7 @@ fn construct_closure_data<'a>(
Stmt::Let(assigned, expr, lambda_set_layout, hole)
}
ClosureRepresentation::Other(Layout::Builtin(Builtin::Int1)) => {
ClosureRepresentation::Other(Layout::Builtin(Builtin::Bool)) => {
debug_assert_eq!(symbols.len(), 0);
debug_assert_eq!(lambda_set.set.len(), 2);
@ -4476,7 +4473,7 @@ fn construct_closure_data<'a>(
Stmt::Let(assigned, expr, lambda_set_layout, hole)
}
ClosureRepresentation::Other(Layout::Builtin(Builtin::Int8)) => {
ClosureRepresentation::Other(Layout::Builtin(Builtin::Int(IntWidth::U8))) => {
debug_assert_eq!(symbols.len(), 0);
debug_assert!(lambda_set.set.len() > 2);
@ -4533,7 +4530,7 @@ fn convert_tag_union<'a>(
BoolUnion { ttrue, .. } => Stmt::Let(
assigned,
Expr::Literal(Literal::Bool(tag_name == ttrue)),
Layout::Builtin(Builtin::Int1),
Layout::Builtin(Builtin::Bool),
hole,
),
ByteUnion(tag_names) => {
@ -4543,7 +4540,7 @@ fn convert_tag_union<'a>(
Some(tag_id) => Stmt::Let(
assigned,
Expr::Literal(Literal::Byte(tag_id as u8)),
Layout::Builtin(Builtin::Int8),
Layout::Builtin(Builtin::Int(IntWidth::U8)),
hole,
),
None => Stmt::RuntimeError("tag must be in its own type"),
@ -5054,7 +5051,7 @@ pub fn from_can<'a>(
Expect(condition, rest) => {
let rest = from_can(env, variable, rest.value, procs, layout_cache);
let bool_layout = Layout::Builtin(Builtin::Int1);
let bool_layout = Layout::Builtin(Builtin::Bool);
let cond_symbol = env.unique_symbol();
let op = LowLevel::ExpectTrue;
@ -7237,8 +7234,8 @@ fn call_specialized_proc<'a>(
pub enum Pattern<'a> {
Identifier(Symbol),
Underscore,
IntLiteral(i128, IntPrecision),
FloatLiteral(u64, FloatPrecision),
IntLiteral(i128, IntWidth),
FloatLiteral(u64, FloatWidth),
DecimalLiteral(RocDec),
BitLiteral {
value: bool,
@ -7318,9 +7315,8 @@ fn from_can_pattern_help<'a>(
Identifier(symbol) => Ok(Pattern::Identifier(*symbol)),
IntLiteral(var, _, int) => {
match num_argument_to_int_or_float(env.subs, env.ptr_bytes, *var, false) {
IntOrFloat::SignedIntType(precision) | IntOrFloat::UnsignedIntType(precision) => {
Ok(Pattern::IntLiteral(*int as i128, precision))
}
IntOrFloat::Natural => todo!(),
IntOrFloat::Int(precision) => Ok(Pattern::IntLiteral(*int as i128, precision)),
other => {
panic!(
"Invalid precision for int pattern: {:?} has {:?}",
@ -7332,10 +7328,10 @@ 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) {
IntOrFloat::SignedIntType(_) | IntOrFloat::UnsignedIntType(_) => {
IntOrFloat::Int(_) | IntOrFloat::Natural => {
panic!("Invalid precision for float pattern {:?}", var)
}
IntOrFloat::BinaryFloatType(precision) => {
IntOrFloat::Float(precision) => {
Ok(Pattern::FloatLiteral(f64::to_bits(*float), precision))
}
IntOrFloat::DecimalFloatType => {
@ -7362,15 +7358,9 @@ fn from_can_pattern_help<'a>(
}
NumLiteral(var, num_str, num) => {
match num_argument_to_int_or_float(env.subs, env.ptr_bytes, *var, false) {
IntOrFloat::SignedIntType(precision) => {
Ok(Pattern::IntLiteral(*num as i128, precision))
}
IntOrFloat::UnsignedIntType(precision) => {
Ok(Pattern::IntLiteral(*num as i128, precision))
}
IntOrFloat::BinaryFloatType(precision) => {
Ok(Pattern::FloatLiteral(*num as u64, precision))
}
IntOrFloat::Int(precision) => Ok(Pattern::IntLiteral(*num as i128, precision)),
IntOrFloat::Float(precision) => Ok(Pattern::FloatLiteral(*num as u64, precision)),
IntOrFloat::Natural => todo!(),
IntOrFloat::DecimalFloatType => {
let dec = match RocDec::from_str(num_str) {
Some(d) => d,
@ -7952,60 +7942,12 @@ fn from_can_record_destruct<'a>(
})
}
#[derive(Debug, Clone, Copy, PartialEq, Hash)]
pub enum IntPrecision {
Usize,
I128,
I64,
I32,
I16,
I8,
}
impl IntPrecision {
pub fn as_layout(&self) -> Layout<'static> {
Layout::Builtin(self.as_builtin())
}
pub fn as_builtin(&self) -> Builtin<'static> {
use IntPrecision::*;
match self {
I128 => Builtin::Int128,
I64 => Builtin::Int64,
I32 => Builtin::Int32,
I16 => Builtin::Int16,
I8 => Builtin::Int8,
Usize => Builtin::Usize,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Hash)]
pub enum FloatPrecision {
F64,
F32,
}
impl FloatPrecision {
pub fn as_layout(&self) -> Layout<'static> {
Layout::Builtin(self.as_builtin())
}
pub fn as_builtin(&self) -> Builtin<'static> {
use FloatPrecision::*;
match self {
F64 => Builtin::Float64,
F32 => Builtin::Float32,
}
}
}
#[derive(Debug)]
pub enum IntOrFloat {
SignedIntType(IntPrecision),
UnsignedIntType(IntPrecision),
BinaryFloatType(FloatPrecision),
Int(IntWidth),
Float(FloatWidth),
DecimalFloatType,
Natural,
}
/// Given the `a` in `Num a`, determines whether it's an int or a float
@ -8015,11 +7957,13 @@ pub fn num_argument_to_int_or_float(
var: Variable,
known_to_be_float: bool,
) -> IntOrFloat {
match subs.get_content_without_compacting(var){
Content::FlexVar(_) | Content::RigidVar(_) if known_to_be_float => IntOrFloat::BinaryFloatType(FloatPrecision::F64),
Content::FlexVar(_) | Content::RigidVar(_) => IntOrFloat::SignedIntType(IntPrecision::I64), // We default (Num *) to I64
match subs.get_content_without_compacting(var) {
Content::FlexVar(_) | Content::RigidVar(_) if known_to_be_float => {
IntOrFloat::Float(FloatWidth::F64)
}
Content::FlexVar(_) | Content::RigidVar(_) => IntOrFloat::Int(IntWidth::I64), // We default (Num *) to I64
Content::Alias(Symbol::NUM_INTEGER, args, _) => {
Content::Alias(Symbol::NUM_INTEGER, args, _) => {
debug_assert!(args.len() == 1);
// Recurse on the second argument
@ -8027,85 +7971,39 @@ pub fn num_argument_to_int_or_float(
num_argument_to_int_or_float(subs, ptr_bytes, var, false)
}
Content::Alias(Symbol::NUM_I128, _, _)
| Content::Alias(Symbol::NUM_SIGNED128, _, _)
| Content::Alias(Symbol::NUM_AT_SIGNED128, _, _) => {
IntOrFloat::SignedIntType(IntPrecision::I128)
}
Content::Alias(Symbol::NUM_INT, _, _)// We default Integer to I64
| Content::Alias(Symbol::NUM_I64, _, _)
| Content::Alias(Symbol::NUM_SIGNED64, _, _)
| Content::Alias(Symbol::NUM_AT_SIGNED64, _, _) => {
IntOrFloat::SignedIntType(IntPrecision::I64)
}
Content::Alias(Symbol::NUM_I32, _, _)
| Content::Alias(Symbol::NUM_SIGNED32, _, _)
| Content::Alias(Symbol::NUM_AT_SIGNED32, _, _) => {
IntOrFloat::SignedIntType(IntPrecision::I32)
}
Content::Alias(Symbol::NUM_I16, _, _)
| Content::Alias(Symbol::NUM_SIGNED16, _, _)
| Content::Alias(Symbol::NUM_AT_SIGNED16, _, _) => {
IntOrFloat::SignedIntType(IntPrecision::I16)
}
Content::Alias(Symbol::NUM_I8, _, _)
| Content::Alias(Symbol::NUM_SIGNED8, _, _)
| Content::Alias(Symbol::NUM_AT_SIGNED8, _, _) => {
IntOrFloat::SignedIntType(IntPrecision::I8)
}
Content::Alias(Symbol::NUM_U128, _, _)
| Content::Alias(Symbol::NUM_UNSIGNED128, _, _)
| Content::Alias(Symbol::NUM_AT_UNSIGNED128, _, _) => {
IntOrFloat::UnsignedIntType(IntPrecision::I128)
}
Content::Alias(Symbol::NUM_U64, _, _)
| Content::Alias(Symbol::NUM_UNSIGNED64, _, _)
| Content::Alias(Symbol::NUM_AT_UNSIGNED64, _, _) => {
IntOrFloat::UnsignedIntType(IntPrecision::I64)
}
Content::Alias(Symbol::NUM_U32, _, _)
| Content::Alias(Symbol::NUM_UNSIGNED32, _, _)
| Content::Alias(Symbol::NUM_AT_UNSIGNED32, _, _) => {
IntOrFloat::UnsignedIntType(IntPrecision::I32)
}
Content::Alias(Symbol::NUM_U16, _, _)
| Content::Alias(Symbol::NUM_UNSIGNED16, _, _)
| Content::Alias(Symbol::NUM_AT_UNSIGNED16, _, _) => {
IntOrFloat::UnsignedIntType(IntPrecision::I16)
}
Content::Alias(Symbol::NUM_U8, _, _)
| Content::Alias(Symbol::NUM_UNSIGNED8, _, _)
| Content::Alias(Symbol::NUM_AT_UNSIGNED8, _, _) => {
IntOrFloat::UnsignedIntType(IntPrecision::I8)
}
Content::Alias(Symbol::NUM_FLOATINGPOINT, args, _) => {
debug_assert!(args.len() == 1);
other @ Content::Alias(symbol, args, _) => {
if let Some(int_width) = IntWidth::try_from_symbol(*symbol) {
return IntOrFloat::Int(int_width);
}
// 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)
}
Content::Alias(Symbol::NUM_FLOAT, _, _) // We default FloatingPoint to F64
| Content::Alias(Symbol::NUM_F64, _, _)
| Content::Alias(Symbol::NUM_BINARY64, _, _)
| Content::Alias(Symbol::NUM_AT_BINARY64, _, _) => {
IntOrFloat::BinaryFloatType(FloatPrecision::F64)
}
Content::Alias(Symbol::NUM_DECIMAL, _, _)
| Content::Alias(Symbol::NUM_AT_DECIMAL, _, _) => {
IntOrFloat::DecimalFloatType
}
Content::Alias(Symbol::NUM_F32, _, _)
| Content::Alias(Symbol::NUM_BINARY32, _, _)
| Content::Alias(Symbol::NUM_AT_BINARY32, _, _) => {
IntOrFloat::BinaryFloatType(FloatPrecision::F32)
}
Content::Alias(Symbol::NUM_NAT, _, _)
| Content::Alias(Symbol::NUM_NATURAL, _, _)
| Content::Alias(Symbol::NUM_AT_NATURAL, _, _) => {
IntOrFloat::UnsignedIntType(IntPrecision::Usize)
if let Some(float_width) = FloatWidth::try_from_symbol(*symbol) {
return IntOrFloat::Float(float_width);
}
match *symbol {
Symbol::NUM_FLOATINGPOINT => {
debug_assert!(args.len() == 1);
// 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)
}
Symbol::NUM_DECIMAL | Symbol::NUM_AT_DECIMAL => {
return IntOrFloat::DecimalFloatType;
}
Symbol::NUM_NAT | Symbol::NUM_NATURAL | Symbol::NUM_AT_NATURAL => {
return IntOrFloat::Natural;
}
_ => panic!(
"Unrecognized Num type argument for var {:?} with Content: {:?}",
var, other
),
}
}
other => {
panic!(
"Unrecognized Num type argument for var {:?} with Content: {:?}",
@ -8187,14 +8085,14 @@ where
hole.clone()
}
},
Layout::Builtin(Builtin::Int1) => {
Layout::Builtin(Builtin::Bool) => {
let closure_tag_id_symbol = closure_data_symbol;
lowlevel_enum_lambda_set_to_switch(
env,
lambda_set.set,
closure_tag_id_symbol,
Layout::Builtin(Builtin::Int1),
Layout::Builtin(Builtin::Bool),
closure_data_symbol,
lambda_set.is_represented(),
to_lowlevel_call,
@ -8203,14 +8101,14 @@ where
hole,
)
}
Layout::Builtin(Builtin::Int8) => {
Layout::Builtin(Builtin::Int(IntWidth::U8)) => {
let closure_tag_id_symbol = closure_data_symbol;
lowlevel_enum_lambda_set_to_switch(
env,
lambda_set.set,
closure_tag_id_symbol,
Layout::Builtin(Builtin::Int8),
Layout::Builtin(Builtin::Int(IntWidth::U8)),
closure_data_symbol,
lambda_set.is_represented(),
to_lowlevel_call,
@ -8351,14 +8249,14 @@ fn match_on_lambda_set<'a>(
hole,
)
}
Layout::Builtin(Builtin::Int1) => {
Layout::Builtin(Builtin::Bool) => {
let closure_tag_id_symbol = closure_data_symbol;
enum_lambda_set_to_switch(
env,
lambda_set.set,
closure_tag_id_symbol,
Layout::Builtin(Builtin::Int1),
Layout::Builtin(Builtin::Bool),
closure_data_symbol,
argument_symbols,
argument_layouts,
@ -8367,14 +8265,14 @@ fn match_on_lambda_set<'a>(
hole,
)
}
Layout::Builtin(Builtin::Int8) => {
Layout::Builtin(Builtin::Int(IntWidth::U8)) => {
let closure_tag_id_symbol = closure_data_symbol;
enum_lambda_set_to_switch(
env,
lambda_set.set,
closure_tag_id_symbol,
Layout::Builtin(Builtin::Int8),
Layout::Builtin(Builtin::Int(IntWidth::U8)),
closure_data_symbol,
argument_symbols,
argument_layouts,
@ -8502,7 +8400,9 @@ fn union_lambda_set_branch_help<'a>(
hole: &'a Stmt<'a>,
) -> Stmt<'a> {
let (argument_layouts, argument_symbols) = match closure_data_layout {
Layout::Struct(&[]) | Layout::Builtin(Builtin::Int1) | Layout::Builtin(Builtin::Int8) => {
Layout::Struct(&[])
| Layout::Builtin(Builtin::Bool)
| Layout::Builtin(Builtin::Int(IntWidth::U8)) => {
(argument_layouts_slice, argument_symbols_slice)
}
_ if lambda_set.member_does_not_need_closure_argument(function_symbol) => {
@ -8627,7 +8527,9 @@ fn enum_lambda_set_branch<'a>(
let assigned = result_symbol;
let (argument_layouts, argument_symbols) = match closure_data_layout {
Layout::Struct(&[]) | Layout::Builtin(Builtin::Int1) | Layout::Builtin(Builtin::Int8) => {
Layout::Struct(&[])
| Layout::Builtin(Builtin::Bool)
| Layout::Builtin(Builtin::Int(IntWidth::U8)) => {
(argument_layouts_slice, argument_symbols_slice)
}
_ => {

View file

@ -1,6 +1,7 @@
use crate::ir::Parens;
use bumpalo::collections::Vec;
use bumpalo::Bump;
use roc_builtins::bitcode::{FloatWidth, IntWidth};
use roc_collections::all::{default_hasher, MutMap};
use roc_module::ident::{Lowercase, TagName};
use roc_module::symbol::{Interns, Symbol};
@ -24,9 +25,6 @@ pub type TagIdIntType = u16;
pub const MAX_ENUM_SIZE: usize = (std::mem::size_of::<TagIdIntType>() * 8) as usize;
const GENERATE_NULLABLE: bool = true;
/// If a (Num *) gets translated to a Layout, this is the numeric type it defaults to.
const DEFAULT_NUM_BUILTIN: Builtin<'_> = Builtin::Int64;
#[derive(Debug, Clone)]
pub enum LayoutProblem {
UnresolvedTypeVar(Variable),
@ -61,60 +59,61 @@ impl<'a> RawFunctionLayout<'a> {
// Ints
Alias(Symbol::NUM_I128, args, _) => {
debug_assert!(args.is_empty());
Ok(Self::ZeroArgumentThunk(Layout::Builtin(Builtin::Int128)))
Ok(Self::ZeroArgumentThunk(Layout::i128()))
}
Alias(Symbol::NUM_I64, args, _) => {
debug_assert!(args.is_empty());
Ok(Self::ZeroArgumentThunk(Layout::Builtin(Builtin::Int64)))
Ok(Self::ZeroArgumentThunk(Layout::i64()))
}
Alias(Symbol::NUM_I32, args, _) => {
debug_assert!(args.is_empty());
Ok(Self::ZeroArgumentThunk(Layout::Builtin(Builtin::Int32)))
Ok(Self::ZeroArgumentThunk(Layout::i32()))
}
Alias(Symbol::NUM_I16, args, _) => {
debug_assert!(args.is_empty());
Ok(Self::ZeroArgumentThunk(Layout::Builtin(Builtin::Int16)))
Ok(Self::ZeroArgumentThunk(Layout::i16()))
}
Alias(Symbol::NUM_I8, args, _) => {
debug_assert!(args.is_empty());
Ok(Self::ZeroArgumentThunk(Layout::Builtin(Builtin::Int8)))
Ok(Self::ZeroArgumentThunk(Layout::i8()))
}
// I think unsigned and signed use the same layout
Alias(Symbol::NUM_U128, args, _) => {
debug_assert!(args.is_empty());
Ok(Self::ZeroArgumentThunk(Layout::Builtin(Builtin::Int128)))
Ok(Self::ZeroArgumentThunk(Layout::u128()))
}
Alias(Symbol::NUM_U64, args, _) => {
debug_assert!(args.is_empty());
Ok(Self::ZeroArgumentThunk(Layout::Builtin(Builtin::Int64)))
Ok(Self::ZeroArgumentThunk(Layout::u64()))
}
Alias(Symbol::NUM_U32, args, _) => {
debug_assert!(args.is_empty());
Ok(Self::ZeroArgumentThunk(Layout::Builtin(Builtin::Int32)))
Ok(Self::ZeroArgumentThunk(Layout::u32()))
}
Alias(Symbol::NUM_U16, args, _) => {
debug_assert!(args.is_empty());
Ok(Self::ZeroArgumentThunk(Layout::Builtin(Builtin::Int16)))
Ok(Self::ZeroArgumentThunk(Layout::u16()))
}
Alias(Symbol::NUM_U8, args, _) => {
debug_assert!(args.is_empty());
Ok(Self::ZeroArgumentThunk(Layout::Builtin(Builtin::Int8)))
}
Alias(Symbol::NUM_NAT, args, _) => {
debug_assert!(args.is_empty());
Ok(Self::ZeroArgumentThunk(Layout::Builtin(Builtin::Usize)))
Ok(Self::ZeroArgumentThunk(Layout::u8()))
}
// Floats
Alias(Symbol::NUM_F64, args, _) => {
debug_assert!(args.is_empty());
Ok(Self::ZeroArgumentThunk(Layout::Builtin(Builtin::Float64)))
Ok(Self::ZeroArgumentThunk(Layout::f64()))
}
Alias(Symbol::NUM_F32, args, _) => {
debug_assert!(args.is_empty());
Ok(Self::ZeroArgumentThunk(Layout::Builtin(Builtin::Float32)))
Ok(Self::ZeroArgumentThunk(Layout::f32()))
}
// Nat
Alias(Symbol::NUM_NAT, args, _) => {
debug_assert!(args.is_empty());
Ok(Self::ZeroArgumentThunk(Layout::usize()))
}
Alias(symbol, _, _) if symbol.is_builtin() => Ok(Self::ZeroArgumentThunk(
@ -315,9 +314,9 @@ impl<'a> UnionLayout<'a> {
fn tag_id_builtin_help(union_size: usize) -> Builtin<'a> {
if union_size <= u8::MAX as usize {
Builtin::Int8
Builtin::Int(IntWidth::U8)
} else if union_size <= u16::MAX as usize {
Builtin::Int16
Builtin::Int(IntWidth::U16)
} else {
panic!("tag union is too big")
}
@ -332,7 +331,7 @@ impl<'a> UnionLayout<'a> {
// The quicksort-benchmarks version of Quicksort.roc segfaults when
// this number is not I64. There must be some dependence on that fact
// somewhere in the code, I have not found where that is yet...
Builtin::Int64
Builtin::Int(IntWidth::U64)
}
UnionLayout::Recursive(tags) => {
let union_size = tags.len();
@ -343,8 +342,8 @@ impl<'a> UnionLayout<'a> {
UnionLayout::NullableWrapped { other_tags, .. } => {
Self::tag_id_builtin_help(other_tags.len() + 1)
}
UnionLayout::NonNullableUnwrapped(_) => Builtin::Int1,
UnionLayout::NullableUnwrapped { .. } => Builtin::Int1,
UnionLayout::NonNullableUnwrapped(_) => Builtin::Bool,
UnionLayout::NullableUnwrapped { .. } => Builtin::Bool,
}
}
@ -546,7 +545,8 @@ impl<'a> LambdaSet<'a> {
// singleton, so we pass no extra argument
argument_layouts
}
Layout::Builtin(Builtin::Int1) | Layout::Builtin(Builtin::Int8) => {
Layout::Builtin(Builtin::Bool)
| Layout::Builtin(Builtin::Int(IntWidth::I8 | IntWidth::U8)) => {
// we don't pass this along either
argument_layouts
}
@ -628,8 +628,8 @@ impl<'a> LambdaSet<'a> {
use UnionVariant::*;
match variant {
Never => Layout::Union(UnionLayout::NonRecursive(&[])),
BoolUnion { .. } => Layout::Builtin(Builtin::Int1),
ByteUnion { .. } => Layout::Builtin(Builtin::Int8),
BoolUnion { .. } => Layout::bool(),
ByteUnion { .. } => Layout::u8(),
Unit | UnitWithArguments => {
// no useful information to store
Layout::Struct(&[])
@ -680,17 +680,11 @@ impl<'a> LambdaSet<'a> {
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum Builtin<'a> {
Int128,
Int64,
Int32,
Int16,
Int8,
Int1,
Int(IntWidth),
Float(FloatWidth),
Bool,
Usize,
Decimal,
Float128,
Float64,
Float32,
Str,
Dict(&'a Layout<'a>, &'a Layout<'a>),
Set(&'a Layout<'a>),
@ -759,61 +753,61 @@ impl<'a> Layout<'a> {
// Ints
Alias(Symbol::NUM_I128, args, _) => {
debug_assert!(args.is_empty());
Ok(Layout::Builtin(Builtin::Int128))
Ok(Layout::i128())
}
Alias(Symbol::NUM_I64, args, _) => {
debug_assert!(args.is_empty());
Ok(Layout::Builtin(Builtin::Int64))
Ok(Layout::i64())
}
Alias(Symbol::NUM_I32, args, _) => {
debug_assert!(args.is_empty());
Ok(Layout::Builtin(Builtin::Int32))
Ok(Layout::i32())
}
Alias(Symbol::NUM_I16, args, _) => {
debug_assert!(args.is_empty());
Ok(Layout::Builtin(Builtin::Int16))
Ok(Layout::i16())
}
Alias(Symbol::NUM_I8, args, _) => {
debug_assert!(args.is_empty());
Ok(Layout::Builtin(Builtin::Int8))
Ok(Layout::i8())
}
// I think unsigned and signed use the same layout
Alias(Symbol::NUM_U128, args, _) => {
debug_assert!(args.is_empty());
Ok(Layout::Builtin(Builtin::Int128))
Ok(Layout::u128())
}
Alias(Symbol::NUM_U64, args, _) => {
debug_assert!(args.is_empty());
Ok(Layout::Builtin(Builtin::Int64))
Ok(Layout::u64())
}
Alias(Symbol::NUM_U32, args, _) => {
debug_assert!(args.is_empty());
Ok(Layout::Builtin(Builtin::Int32))
Ok(Layout::u32())
}
Alias(Symbol::NUM_U16, args, _) => {
debug_assert!(args.is_empty());
Ok(Layout::Builtin(Builtin::Int16))
Ok(Layout::u16())
}
Alias(Symbol::NUM_U8, args, _) => {
debug_assert!(args.is_empty());
Ok(Layout::Builtin(Builtin::Int8))
Ok(Layout::u8())
}
// Floats
Alias(Symbol::NUM_F64, args, _) => {
debug_assert!(args.is_empty());
Ok(Layout::Builtin(Builtin::Float64))
Ok(Layout::f64())
}
Alias(Symbol::NUM_F32, args, _) => {
debug_assert!(args.is_empty());
Ok(Layout::Builtin(Builtin::Float32))
Ok(Layout::f32())
}
// Nat
Alias(Symbol::NUM_NAT, args, _) => {
debug_assert!(args.is_empty());
Ok(Layout::Builtin(Builtin::Usize))
Ok(Layout::usize())
}
Alias(_, _, var) => Self::from_var(env, var),
@ -1148,6 +1142,76 @@ impl<'a> LayoutCache<'a> {
// placeholder for the type ven_ena::unify::Snapshot<ven_ena::unify::InPlace<CachedVariable<'a>>>
pub struct SnapshotKeyPlaceholder;
impl<'a> Layout<'a> {
pub fn int_width(width: IntWidth) -> Layout<'a> {
Layout::Builtin(Builtin::Int(width))
}
pub fn float_width(width: FloatWidth) -> Layout<'a> {
Layout::Builtin(Builtin::Float(width))
}
pub fn f64() -> Layout<'a> {
Layout::Builtin(Builtin::Float(FloatWidth::F64))
}
pub fn f32() -> Layout<'a> {
Layout::Builtin(Builtin::Float(FloatWidth::F32))
}
pub fn usize() -> Layout<'a> {
Layout::Builtin(Builtin::Usize)
}
pub fn bool() -> Layout<'a> {
Layout::Builtin(Builtin::Bool)
}
pub fn u8() -> Layout<'a> {
Layout::Builtin(Builtin::Int(IntWidth::U8))
}
pub fn u16() -> Layout<'a> {
Layout::Builtin(Builtin::Int(IntWidth::U16))
}
pub fn u32() -> Layout<'a> {
Layout::Builtin(Builtin::Int(IntWidth::U32))
}
pub fn u64() -> Layout<'a> {
Layout::Builtin(Builtin::Int(IntWidth::U64))
}
pub fn u128() -> Layout<'a> {
Layout::Builtin(Builtin::Int(IntWidth::U128))
}
pub fn i8() -> Layout<'a> {
Layout::Builtin(Builtin::Int(IntWidth::I8))
}
pub fn i16() -> Layout<'a> {
Layout::Builtin(Builtin::Int(IntWidth::I16))
}
pub fn i32() -> Layout<'a> {
Layout::Builtin(Builtin::Int(IntWidth::I32))
}
pub fn i64() -> Layout<'a> {
Layout::Builtin(Builtin::Int(IntWidth::I64))
}
pub fn i128() -> Layout<'a> {
Layout::Builtin(Builtin::Int(IntWidth::I128))
}
pub fn default_integer() -> Layout<'a> {
Layout::i64()
}
}
impl<'a> Builtin<'a> {
const I128_SIZE: u32 = std::mem::size_of::<i128>() as u32;
const I64_SIZE: u32 = std::mem::size_of::<i64>() as u32;
@ -1177,17 +1241,11 @@ impl<'a> Builtin<'a> {
use Builtin::*;
match self {
Int128 => Builtin::I128_SIZE,
Int64 => Builtin::I64_SIZE,
Int32 => Builtin::I32_SIZE,
Int16 => Builtin::I16_SIZE,
Int8 => Builtin::I8_SIZE,
Int1 => Builtin::I1_SIZE,
Int(int) => int.stack_size(),
Float(float) => float.stack_size(),
Bool => Builtin::I1_SIZE,
Usize => pointer_size,
Decimal => Builtin::DECIMAL_SIZE,
Float128 => Builtin::F128_SIZE,
Float64 => Builtin::F64_SIZE,
Float32 => Builtin::F32_SIZE,
Str | EmptyStr => Builtin::STR_WORDS * pointer_size,
Dict(_, _) | EmptyDict => Builtin::DICT_WORDS * pointer_size,
Set(_) | EmptySet => Builtin::SET_WORDS * pointer_size,
@ -1203,17 +1261,11 @@ impl<'a> Builtin<'a> {
// since both of those are one pointer size, the alignment of that structure is a pointer
// size
match self {
Int128 => align_of::<i128>() as u32,
Int64 => align_of::<i64>() as u32,
Int32 => align_of::<i32>() as u32,
Int16 => align_of::<i16>() as u32,
Int8 => align_of::<i8>() as u32,
Int1 => align_of::<bool>() as u32,
Int(int_width) => int_width.alignment_bytes(),
Float(float_width) => float_width.alignment_bytes(),
Bool => align_of::<bool>() as u32,
Usize => pointer_size,
Decimal => align_of::<i128>() as u32,
Float128 => align_of::<i128>() as u32,
Float64 => align_of::<f64>() as u32,
Float32 => align_of::<f32>() as u32,
Dict(_, _) | EmptyDict => pointer_size,
Set(_) | EmptySet => pointer_size,
// we often treat these as i128 (64-bit systems)
@ -1230,8 +1282,9 @@ impl<'a> Builtin<'a> {
use Builtin::*;
match self {
Int128 | Int64 | Int32 | Int16 | Int8 | Int1 | Usize | Decimal | Float128 | Float64
| Float32 | EmptyStr | EmptyDict | EmptyList | EmptySet => true,
Int(_) | Usize | Float(_) | Bool | Decimal | EmptyStr | EmptyDict | EmptyList
| EmptySet => true,
Str | Dict(_, _) | Set(_) | List(_) => false,
}
}
@ -1241,8 +1294,8 @@ impl<'a> Builtin<'a> {
use Builtin::*;
match self {
Int128 | Int64 | Int32 | Int16 | Int8 | Int1 | Usize | Decimal | Float128 | Float64
| Float32 | EmptyStr | EmptyDict | EmptyList | EmptySet => false,
Int(_) | Usize | Float(_) | Bool | Decimal | EmptyStr | EmptyDict | EmptyList
| EmptySet => false,
List(_) => true,
Str | Dict(_, _) | Set(_) => true,
@ -1258,17 +1311,36 @@ impl<'a> Builtin<'a> {
use Builtin::*;
match self {
Int128 => alloc.text("Int128"),
Int64 => alloc.text("Int64"),
Int32 => alloc.text("Int32"),
Int16 => alloc.text("Int16"),
Int8 => alloc.text("Int8"),
Int1 => alloc.text("Int1"),
Int(int_width) => {
use IntWidth::*;
match int_width {
I128 => alloc.text("I128"),
I64 => alloc.text("I64"),
I32 => alloc.text("I32"),
I16 => alloc.text("I16"),
I8 => alloc.text("I8"),
U128 => alloc.text("U128"),
U64 => alloc.text("U64"),
U32 => alloc.text("U32"),
U16 => alloc.text("U16"),
U8 => alloc.text("U8"),
}
}
Float(float_width) => {
use FloatWidth::*;
match float_width {
F128 => alloc.text("Float128"),
F64 => alloc.text("Float64"),
F32 => alloc.text("Float32"),
}
}
Bool => alloc.text("Int1"),
Usize => alloc.text("Usize"),
Decimal => alloc.text("Decimal"),
Float128 => alloc.text("Float128"),
Float64 => alloc.text("Float64"),
Float32 => alloc.text("Float32"),
EmptyStr => alloc.text("EmptyStr"),
EmptyList => alloc.text("EmptyList"),
@ -1292,17 +1364,11 @@ impl<'a> Builtin<'a> {
pub fn allocation_alignment_bytes(&self, pointer_size: u32) -> u32 {
let allocation = match self {
Builtin::Int128
| Builtin::Int64
| Builtin::Int32
| Builtin::Int16
| Builtin::Int8
| Builtin::Int1
Builtin::Int(_)
| Builtin::Float(_)
| Builtin::Bool
| Builtin::Usize
| Builtin::Decimal
| Builtin::Float128
| Builtin::Float64
| Builtin::Float32 => unreachable!("not heap-allocated"),
| Builtin::Decimal => unreachable!("not heap-allocated"),
Builtin::Str => pointer_size,
Builtin::Dict(k, v) => k
.alignment_bytes(pointer_size)
@ -1342,44 +1408,44 @@ fn layout_from_flat_type<'a>(
Symbol::NUM_I128 => {
debug_assert_eq!(args.len(), 0);
Ok(Layout::Builtin(Builtin::Int128))
Ok(Layout::i128())
}
Symbol::NUM_I64 => {
debug_assert_eq!(args.len(), 0);
Ok(Layout::Builtin(Builtin::Int64))
Ok(Layout::i64())
}
Symbol::NUM_I32 => {
debug_assert_eq!(args.len(), 0);
Ok(Layout::Builtin(Builtin::Int32))
Ok(Layout::i32())
}
Symbol::NUM_I16 => {
debug_assert_eq!(args.len(), 0);
Ok(Layout::Builtin(Builtin::Int16))
Ok(Layout::i16())
}
Symbol::NUM_I8 => {
debug_assert_eq!(args.len(), 0);
Ok(Layout::Builtin(Builtin::Int8))
Ok(Layout::i8())
}
Symbol::NUM_U128 => {
debug_assert_eq!(args.len(), 0);
Ok(Layout::Builtin(Builtin::Int128))
Ok(Layout::u128())
}
Symbol::NUM_U64 => {
debug_assert_eq!(args.len(), 0);
Ok(Layout::Builtin(Builtin::Int64))
Ok(Layout::u64())
}
Symbol::NUM_U32 => {
debug_assert_eq!(args.len(), 0);
Ok(Layout::Builtin(Builtin::Int32))
Ok(Layout::u32())
}
Symbol::NUM_U16 => {
debug_assert_eq!(args.len(), 0);
Ok(Layout::Builtin(Builtin::Int16))
Ok(Layout::u16())
}
Symbol::NUM_U8 => {
debug_assert_eq!(args.len(), 0);
Ok(Layout::Builtin(Builtin::Int8))
Ok(Layout::u8())
}
// Floats
@ -1389,11 +1455,11 @@ fn layout_from_flat_type<'a>(
}
Symbol::NUM_F64 => {
debug_assert_eq!(args.len(), 0);
Ok(Layout::Builtin(Builtin::Float64))
Ok(Layout::f64())
}
Symbol::NUM_F32 => {
debug_assert_eq!(args.len(), 0);
Ok(Layout::Builtin(Builtin::Float32))
Ok(Layout::f32())
}
Symbol::NUM_NUM | Symbol::NUM_AT_NUM => {
@ -2295,8 +2361,8 @@ fn layout_from_tag_union<'a>(
match variant {
Never => Layout::Union(UnionLayout::NonRecursive(&[])),
Unit | UnitWithArguments => Layout::Struct(&[]),
BoolUnion { .. } => Layout::Builtin(Builtin::Int1),
ByteUnion(_) => Layout::Builtin(Builtin::Int8),
BoolUnion { .. } => Layout::bool(),
ByteUnion(_) => Layout::u8(),
Newtype {
arguments: field_layouts,
..
@ -2396,30 +2462,32 @@ fn layout_from_num_content<'a>(content: &Content) -> Result<Layout<'a>, LayoutPr
// type variable, then assume it's a 64-bit integer.
//
// (e.g. for (5 + 5) assume both 5s are 64-bit integers.)
Ok(Layout::Builtin(DEFAULT_NUM_BUILTIN))
Ok(Layout::default_integer())
}
Structure(Apply(symbol, args)) => match *symbol {
// Ints
Symbol::NUM_NAT => Ok(Layout::Builtin(Builtin::Usize)),
Symbol::NUM_NAT => Ok(Layout::usize()),
Symbol::NUM_INTEGER => Ok(Layout::Builtin(Builtin::Int64)),
Symbol::NUM_I128 => Ok(Layout::Builtin(Builtin::Int128)),
Symbol::NUM_I64 => Ok(Layout::Builtin(Builtin::Int64)),
Symbol::NUM_I32 => Ok(Layout::Builtin(Builtin::Int32)),
Symbol::NUM_I16 => Ok(Layout::Builtin(Builtin::Int16)),
Symbol::NUM_I8 => Ok(Layout::Builtin(Builtin::Int8)),
Symbol::NUM_INTEGER => Ok(Layout::i64()),
Symbol::NUM_I128 => Ok(Layout::i128()),
Symbol::NUM_I64 => Ok(Layout::i64()),
Symbol::NUM_I32 => Ok(Layout::i32()),
Symbol::NUM_I16 => Ok(Layout::i16()),
Symbol::NUM_I8 => Ok(Layout::i8()),
Symbol::NUM_U128 => Ok(Layout::Builtin(Builtin::Int128)),
Symbol::NUM_U64 => Ok(Layout::Builtin(Builtin::Int64)),
Symbol::NUM_U32 => Ok(Layout::Builtin(Builtin::Int32)),
Symbol::NUM_U16 => Ok(Layout::Builtin(Builtin::Int16)),
Symbol::NUM_U8 => Ok(Layout::Builtin(Builtin::Int8)),
Symbol::NUM_U128 => Ok(Layout::u128()),
Symbol::NUM_U64 => Ok(Layout::u64()),
Symbol::NUM_U32 => Ok(Layout::u32()),
Symbol::NUM_U16 => Ok(Layout::u16()),
Symbol::NUM_U8 => Ok(Layout::u8()),
// Floats
Symbol::NUM_FLOATINGPOINT => Ok(Layout::Builtin(Builtin::Float64)),
Symbol::NUM_FLOATINGPOINT => Ok(Layout::f64()),
Symbol::NUM_F64 => Ok(Layout::f64()),
Symbol::NUM_F32 => Ok(Layout::f32()),
// Dec
Symbol::NUM_DEC => Ok(Layout::Builtin(Builtin::Decimal)),
Symbol::NUM_F64 => Ok(Layout::Builtin(Builtin::Float64)),
Symbol::NUM_F32 => Ok(Layout::Builtin(Builtin::Float32)),
_ => {
panic!(
@ -2451,26 +2519,29 @@ fn unwrap_num_tag<'a>(subs: &Subs, var: Variable) -> Result<Layout<'a>, LayoutPr
Content::Alias(symbol, args, _) => {
debug_assert!(args.is_empty());
let builtin = match *symbol {
Symbol::NUM_SIGNED128 => Builtin::Int128,
Symbol::NUM_SIGNED64 => Builtin::Int64,
Symbol::NUM_SIGNED32 => Builtin::Int32,
Symbol::NUM_SIGNED16 => Builtin::Int16,
Symbol::NUM_SIGNED8 => Builtin::Int8,
Symbol::NUM_UNSIGNED128 => Builtin::Int128,
Symbol::NUM_UNSIGNED64 => Builtin::Int64,
Symbol::NUM_UNSIGNED32 => Builtin::Int32,
Symbol::NUM_UNSIGNED16 => Builtin::Int16,
Symbol::NUM_UNSIGNED8 => Builtin::Int8,
Symbol::NUM_NATURAL => Builtin::Usize,
let width = match *symbol {
Symbol::NUM_SIGNED128 => IntWidth::I128,
Symbol::NUM_SIGNED64 => IntWidth::I64,
Symbol::NUM_SIGNED32 => IntWidth::I32,
Symbol::NUM_SIGNED16 => IntWidth::I16,
Symbol::NUM_SIGNED8 => IntWidth::I8,
Symbol::NUM_UNSIGNED128 => IntWidth::U128,
Symbol::NUM_UNSIGNED64 => IntWidth::U64,
Symbol::NUM_UNSIGNED32 => IntWidth::U32,
Symbol::NUM_UNSIGNED16 => IntWidth::U16,
Symbol::NUM_UNSIGNED8 => IntWidth::U8,
Symbol::NUM_NATURAL => {
return Ok(Layout::usize());
}
_ => unreachable!("not a valid int variant: {:?} {:?}", symbol, args),
};
Ok(Layout::Builtin(builtin))
Ok(Layout::Builtin(Builtin::Int(width)))
}
Content::FlexVar(_) | Content::RigidVar(_) => {
// default to i64
Ok(Layout::Builtin(Builtin::Int64))
Ok(Layout::i64())
}
_ => unreachable!("not a valid int variant: {:?}", precision),
}
@ -2486,12 +2557,12 @@ fn unwrap_num_tag<'a>(subs: &Subs, var: Variable) -> Result<Layout<'a>, LayoutPr
Content::Alias(Symbol::NUM_BINARY32, args, _) => {
debug_assert!(args.is_empty());
Ok(Layout::Builtin(Builtin::Float32))
Ok(Layout::f32())
}
Content::Alias(Symbol::NUM_BINARY64, args, _) => {
debug_assert!(args.is_empty());
Ok(Layout::Builtin(Builtin::Float64))
Ok(Layout::f64())
}
Content::Alias(Symbol::NUM_DECIMAL, args, _) => {
debug_assert!(args.is_empty());
@ -2500,14 +2571,14 @@ fn unwrap_num_tag<'a>(subs: &Subs, var: Variable) -> Result<Layout<'a>, LayoutPr
}
Content::FlexVar(_) | Content::RigidVar(_) => {
// default to f64
Ok(Layout::Builtin(Builtin::Float64))
Ok(Layout::f64())
}
_ => unreachable!("not a valid float variant: {:?}", precision),
}
}
Content::FlexVar(_) | Content::RigidVar(_) => {
// If this was still a (Num *) then default to compiling it to i64
Ok(Layout::Builtin(DEFAULT_NUM_BUILTIN))
Ok(Layout::default_integer())
}
other => {
todo!("TODO non structure Num.@Num flat_type {:?}", other);