Use usize length, no capacity for llvm List

This commit is contained in:
Richard Feldman 2020-03-18 19:15:58 -04:00
parent 59368caa0c
commit 43c4fadd6e
3 changed files with 79 additions and 56 deletions

View file

@ -3,13 +3,13 @@ use bumpalo::Bump;
use inkwell::builder::Builder; use inkwell::builder::Builder;
use inkwell::context::Context; use inkwell::context::Context;
use inkwell::module::{Linkage, Module}; use inkwell::module::{Linkage, Module};
use inkwell::types::BasicTypeEnum; use inkwell::types::{BasicTypeEnum, IntType};
use inkwell::values::BasicValueEnum::{self, *}; use inkwell::values::BasicValueEnum::{self, *};
use inkwell::values::{FunctionValue, IntValue, PointerValue}; use inkwell::values::{FunctionValue, IntValue, PointerValue};
use inkwell::{AddressSpace, FloatPredicate, IntPredicate}; use inkwell::{AddressSpace, FloatPredicate, IntPredicate};
use crate::llvm::convert::{ use crate::llvm::convert::{
basic_type_from_layout, collection_wrapper, get_array_type, get_fn_type, basic_type_from_layout, collection_wrapper, get_array_type, get_fn_type, ptr_int,
}; };
use roc_collections::all::ImMap; use roc_collections::all::ImMap;
use roc_module::symbol::{Interns, Symbol}; use roc_module::symbol::{Interns, Symbol};
@ -32,7 +32,13 @@ pub struct Env<'a, 'ctx, 'env> {
pub builder: &'env Builder<'ctx>, pub builder: &'env Builder<'ctx>,
pub module: &'ctx Module<'ctx>, pub module: &'ctx Module<'ctx>,
pub interns: Interns, pub interns: Interns,
pub pointer_bytes: u32, pub ptr_bytes: u32,
}
impl<'a, 'ctx, 'env> Env<'a, 'ctx, 'env> {
pub fn ptr_int(&self) -> IntType<'ctx> {
ptr_int(self.context, self.ptr_bytes)
}
} }
pub fn build_expr<'a, 'ctx, 'env>( pub fn build_expr<'a, 'ctx, 'env>(
@ -75,7 +81,8 @@ pub fn build_expr<'a, 'ctx, 'env>(
ret_layout, ret_layout,
cond_layout, cond_layout,
} => { } => {
let ret_type = basic_type_from_layout(env.arena, env.context, &ret_layout); let ret_type =
basic_type_from_layout(env.arena, env.context, &ret_layout, env.ptr_bytes);
let switch_args = SwitchArgs { let switch_args = SwitchArgs {
cond_layout: cond_layout.clone(), cond_layout: cond_layout.clone(),
cond_expr: cond, cond_expr: cond,
@ -92,7 +99,7 @@ pub fn build_expr<'a, 'ctx, 'env>(
for (symbol, layout, expr) in stores.iter() { for (symbol, layout, expr) in stores.iter() {
let val = build_expr(env, &scope, parent, &expr, procs); let val = build_expr(env, &scope, parent, &expr, procs);
let expr_bt = basic_type_from_layout(env.arena, context, &layout); let expr_bt = basic_type_from_layout(env.arena, context, &layout, env.ptr_bytes);
let alloca = create_entry_block_alloca( let alloca = create_entry_block_alloca(
env, env,
parent, parent,
@ -209,13 +216,13 @@ pub fn build_expr<'a, 'ctx, 'env>(
} }
Array { elem_layout, elems } => { Array { elem_layout, elems } => {
let ctx = env.context; let ctx = env.context;
let elem_type = basic_type_from_layout(env.arena, ctx, elem_layout); let elem_type = basic_type_from_layout(env.arena, ctx, elem_layout, env.ptr_bytes);
let builder = env.builder; let builder = env.builder;
if elems.is_empty() { if elems.is_empty() {
let array_type = get_array_type(&elem_type, 0); let array_type = get_array_type(&elem_type, 0);
let ptr_type = array_type.ptr_type(AddressSpace::Generic); let ptr_type = array_type.ptr_type(AddressSpace::Generic);
let struct_type = collection_wrapper(ctx, ptr_type); let struct_type = collection_wrapper(ctx, ptr_type, env.ptr_bytes);
// The first field in the struct should be the pointer. // The first field in the struct should be the pointer.
let struct_val = builder let struct_val = builder
@ -230,11 +237,12 @@ pub fn build_expr<'a, 'ctx, 'env>(
BasicValueEnum::StructValue(struct_val.into_struct_value()) BasicValueEnum::StructValue(struct_val.into_struct_value())
} else { } else {
let len_u64 = elems.len() as u64; let len_u64 = elems.len() as u64;
let elem_bytes = elem_layout.stack_size(env.pointer_bytes) as u64; let elem_bytes = elem_layout.stack_size(env.ptr_bytes) as u64;
let ptr = { let ptr = {
let bytes_len = elem_bytes * len_u64; let bytes_len = elem_bytes * len_u64;
let len = ctx.i32_type().const_int(bytes_len, false); let len_type = env.ptr_int();
let len = len_type.const_int(bytes_len, false);
env.builder env.builder
.build_array_malloc(elem_type, len, "create_list_ptr") .build_array_malloc(elem_type, len, "create_list_ptr")
@ -252,8 +260,8 @@ pub fn build_expr<'a, 'ctx, 'env>(
} }
let ptr_val = BasicValueEnum::PointerValue(ptr); let ptr_val = BasicValueEnum::PointerValue(ptr);
let struct_type = collection_wrapper(ctx, ptr.get_type()); let struct_type = collection_wrapper(ctx, ptr.get_type(), env.ptr_bytes);
let len = BasicValueEnum::IntValue(ctx.i32_type().const_int(len_u64, false)); let len = BasicValueEnum::IntValue(env.ptr_int().const_int(len_u64, false));
let mut struct_val; let mut struct_val;
// Field 0: pointer // Field 0: pointer
@ -271,16 +279,6 @@ pub fn build_expr<'a, 'ctx, 'env>(
.build_insert_value(struct_val, len, Builtin::WRAPPER_LEN, "insert_len") .build_insert_value(struct_val, len, Builtin::WRAPPER_LEN, "insert_len")
.unwrap(); .unwrap();
// Field 2: capacity (initially set to length)
struct_val = builder
.build_insert_value(
struct_val,
len,
Builtin::WRAPPER_CAPACITY,
"insert_capacity",
)
.unwrap();
BasicValueEnum::StructValue(struct_val.into_struct_value()) BasicValueEnum::StructValue(struct_val.into_struct_value())
} }
} }
@ -296,7 +294,8 @@ pub fn build_expr<'a, 'ctx, 'env>(
for (field_expr, field_layout) in sorted_fields.iter() { for (field_expr, field_layout) in sorted_fields.iter() {
let val = build_expr(env, &scope, parent, field_expr, procs); let val = build_expr(env, &scope, parent, field_expr, procs);
let field_type = basic_type_from_layout(env.arena, env.context, &field_layout); let field_type =
basic_type_from_layout(env.arena, env.context, &field_layout, env.ptr_bytes);
field_types.push(field_type); field_types.push(field_type);
field_vals.push(val); field_vals.push(val);
@ -332,7 +331,8 @@ pub fn build_expr<'a, 'ctx, 'env>(
for (field_expr, field_layout) in it { for (field_expr, field_layout) in it {
let val = build_expr(env, &scope, parent, field_expr, procs); let val = build_expr(env, &scope, parent, field_expr, procs);
let field_type = basic_type_from_layout(env.arena, env.context, &field_layout); let field_type =
basic_type_from_layout(env.arena, env.context, &field_layout, env.ptr_bytes);
field_types.push(field_type); field_types.push(field_type);
field_vals.push(val); field_vals.push(val);
@ -358,7 +358,7 @@ pub fn build_expr<'a, 'ctx, 'env>(
tag_id, tag_id,
.. ..
} => { } => {
let ptr_size = env.pointer_bytes; let ptr_size = env.ptr_bytes;
let whole_size = tag_layout.stack_size(ptr_size); let whole_size = tag_layout.stack_size(ptr_size);
let mut filler = tag_layout.stack_size(ptr_size); let mut filler = tag_layout.stack_size(ptr_size);
@ -390,7 +390,8 @@ pub fn build_expr<'a, 'ctx, 'env>(
for (field_expr, field_layout) in arguments.iter() { for (field_expr, field_layout) in arguments.iter() {
let val = build_expr(env, &scope, parent, field_expr, procs); let val = build_expr(env, &scope, parent, field_expr, procs);
let field_type = basic_type_from_layout(env.arena, env.context, &field_layout); let field_type =
basic_type_from_layout(env.arena, env.context, &field_layout, ptr_size);
field_types.push(field_type); field_types.push(field_type);
field_vals.push(val); field_vals.push(val);
@ -529,9 +530,11 @@ pub fn build_expr<'a, 'ctx, 'env>(
// Determine types, assumes the descriminant is in the field layouts // Determine types, assumes the descriminant is in the field layouts
let num_fields = field_layouts.len(); let num_fields = field_layouts.len();
let mut field_types = Vec::with_capacity_in(num_fields, env.arena); let mut field_types = Vec::with_capacity_in(num_fields, env.arena);
let ptr_bytes = env.ptr_bytes;
for field_layout in field_layouts.iter() { for field_layout in field_layouts.iter() {
let field_type = basic_type_from_layout(env.arena, env.context, &field_layout); let field_type =
basic_type_from_layout(env.arena, env.context, &field_layout, ptr_bytes);
field_types.push(field_type); field_types.push(field_type);
} }
@ -583,7 +586,7 @@ fn build_branch2<'a, 'ctx, 'env>(
procs: &Procs<'a>, procs: &Procs<'a>,
) -> BasicValueEnum<'ctx> { ) -> BasicValueEnum<'ctx> {
let ret_layout = cond.ret_layout; let ret_layout = cond.ret_layout;
let ret_type = basic_type_from_layout(env.arena, env.context, &ret_layout); let ret_type = basic_type_from_layout(env.arena, env.context, &ret_layout, env.ptr_bytes);
let cond_expr = build_expr(env, scope, parent, cond.cond, procs); let cond_expr = build_expr(env, scope, parent, cond.cond, procs);
@ -778,12 +781,12 @@ pub fn build_proc_header<'a, 'ctx, 'env>(
let args = proc.args; let args = proc.args;
let arena = env.arena; let arena = env.arena;
let context = &env.context; let context = &env.context;
let ret_type = basic_type_from_layout(arena, context, &proc.ret_layout); let ret_type = basic_type_from_layout(arena, context, &proc.ret_layout, env.ptr_bytes);
let mut arg_basic_types = Vec::with_capacity_in(args.len(), arena); let mut arg_basic_types = Vec::with_capacity_in(args.len(), arena);
let mut arg_symbols = Vec::new_in(arena); let mut arg_symbols = Vec::new_in(arena);
for (layout, arg_symbol) in args.iter() { for (layout, arg_symbol) in args.iter() {
let arg_type = basic_type_from_layout(arena, env.context, &layout); let arg_type = basic_type_from_layout(arena, env.context, &layout, env.ptr_bytes);
arg_basic_types.push(arg_type); arg_basic_types.push(arg_type);
arg_symbols.push(arg_symbol); arg_symbols.push(arg_symbol);
@ -925,11 +928,8 @@ fn call_with_args<'a, 'ctx, 'env>(
let wrapper_struct = args[0].into_struct_value(); let wrapper_struct = args[0].into_struct_value();
let builder = env.builder; let builder = env.builder;
// Get the 32-bit int length // Get the usize int length
let i32_val = builder.build_extract_value(wrapper_struct, Builtin::WRAPPER_LEN, "unwrapped_list_len").unwrap().into_int_value(); builder.build_extract_value(wrapper_struct, Builtin::WRAPPER_LEN, "unwrapped_list_len").unwrap().into_int_value().into()
// cast the 32-bit length to a 64-bit int
BasicValueEnum::IntValue(builder.build_int_cast(i32_val, env.context.i64_type(), "i32_to_i64"))
} }
Symbol::LIST_IS_EMPTY => { Symbol::LIST_IS_EMPTY => {
debug_assert!(args.len() == 1); debug_assert!(args.len() == 1);
@ -937,7 +937,7 @@ fn call_with_args<'a, 'ctx, 'env>(
let list_struct = args[0].into_struct_value(); let list_struct = args[0].into_struct_value();
let builder = env.builder; let builder = env.builder;
let list_len = builder.build_extract_value(list_struct, 1, "unwrapped_list_len").unwrap().into_int_value(); let list_len = builder.build_extract_value(list_struct, 1, "unwrapped_list_len").unwrap().into_int_value();
let zero = env.context.i32_type().const_zero(); let zero = env.ptr_int().const_zero();
let answer = builder.build_int_compare(IntPredicate::EQ, list_len, zero, "is_zero"); let answer = builder.build_int_compare(IntPredicate::EQ, list_len, zero, "is_zero");
BasicValueEnum::IntValue(answer) BasicValueEnum::IntValue(answer)

View file

@ -2,7 +2,7 @@ use bumpalo::collections::Vec;
use bumpalo::Bump; use bumpalo::Bump;
use inkwell::context::Context; use inkwell::context::Context;
use inkwell::types::BasicTypeEnum::{self, *}; use inkwell::types::BasicTypeEnum::{self, *};
use inkwell::types::{ArrayType, BasicType, FunctionType, PointerType, StructType}; use inkwell::types::{ArrayType, BasicType, FunctionType, IntType, PointerType, StructType};
use inkwell::AddressSpace; use inkwell::AddressSpace;
use roc_mono::layout::Layout; use roc_mono::layout::Layout;
@ -38,17 +38,20 @@ pub fn basic_type_from_layout<'ctx>(
arena: &Bump, arena: &Bump,
context: &'ctx Context, context: &'ctx Context,
layout: &Layout<'_>, layout: &Layout<'_>,
ptr_bytes: u32,
) -> BasicTypeEnum<'ctx> { ) -> BasicTypeEnum<'ctx> {
use roc_mono::layout::Builtin::*; use roc_mono::layout::Builtin::*;
use roc_mono::layout::Layout::*; use roc_mono::layout::Layout::*;
match layout { match layout {
FunctionPointer(args, ret_layout) => { FunctionPointer(args, ret_layout) => {
let ret_type = basic_type_from_layout(arena, context, &ret_layout); let ret_type = basic_type_from_layout(arena, context, &ret_layout, ptr_bytes);
let mut arg_basic_types = Vec::with_capacity_in(args.len(), arena); let mut arg_basic_types = Vec::with_capacity_in(args.len(), arena);
for arg_layout in args.iter() { for arg_layout in args.iter() {
arg_basic_types.push(basic_type_from_layout(arena, context, arg_layout)); arg_basic_types.push(basic_type_from_layout(
arena, context, arg_layout, ptr_bytes,
));
} }
let fn_type = get_fn_type(&ret_type, arg_basic_types.into_bump_slice()); let fn_type = get_fn_type(&ret_type, arg_basic_types.into_bump_slice());
@ -61,7 +64,12 @@ pub fn basic_type_from_layout<'ctx>(
let mut field_types = Vec::with_capacity_in(sorted_fields.len(), arena); let mut field_types = Vec::with_capacity_in(sorted_fields.len(), arena);
for (_, field_layout) in sorted_fields.iter() { for (_, field_layout) in sorted_fields.iter() {
field_types.push(basic_type_from_layout(arena, context, field_layout)); field_types.push(basic_type_from_layout(
arena,
context,
field_layout,
ptr_bytes,
));
} }
context context
@ -75,7 +83,7 @@ pub fn basic_type_from_layout<'ctx>(
let mut field_types = Vec::with_capacity_in(layouts.len(), arena); let mut field_types = Vec::with_capacity_in(layouts.len(), arena);
for layout in layouts.iter() { for layout in layouts.iter() {
field_types.push(basic_type_from_layout(arena, context, layout)); field_types.push(basic_type_from_layout(arena, context, layout, ptr_bytes));
} }
context context
@ -107,17 +115,17 @@ pub fn basic_type_from_layout<'ctx>(
Map(_, _) | EmptyMap => panic!("TODO layout_to_basic_type for Builtin::Map"), Map(_, _) | EmptyMap => panic!("TODO layout_to_basic_type for Builtin::Map"),
Set(_) | EmptySet => panic!("TODO layout_to_basic_type for Builtin::Set"), Set(_) | EmptySet => panic!("TODO layout_to_basic_type for Builtin::Set"),
List(elem_layout) => { List(elem_layout) => {
let ptr_type = basic_type_from_layout(arena, context, elem_layout) let ptr_type = basic_type_from_layout(arena, context, elem_layout, ptr_bytes)
.ptr_type(AddressSpace::Generic); .ptr_type(AddressSpace::Generic);
collection_wrapper(context, ptr_type).into() collection_wrapper(context, ptr_type, ptr_bytes).into()
} }
EmptyList => { EmptyList => {
let array_type = let array_type =
get_array_type(&context.opaque_struct_type("empty_list_elem").into(), 0); get_array_type(&context.opaque_struct_type("empty_list_elem").into(), 0);
let ptr_type = array_type.ptr_type(AddressSpace::Generic); let ptr_type = array_type.ptr_type(AddressSpace::Generic);
collection_wrapper(context, ptr_type).into() collection_wrapper(context, ptr_type, ptr_bytes).into()
} }
}, },
} }
@ -127,9 +135,24 @@ pub fn basic_type_from_layout<'ctx>(
pub fn collection_wrapper<'ctx>( pub fn collection_wrapper<'ctx>(
ctx: &'ctx Context, ctx: &'ctx Context,
ptr_type: PointerType<'ctx>, ptr_type: PointerType<'ctx>,
ptr_bytes: u32,
) -> StructType<'ctx> { ) -> StructType<'ctx> {
let ptr_type_enum = BasicTypeEnum::PointerType(ptr_type); let ptr_type_enum = BasicTypeEnum::PointerType(ptr_type);
let u32_type = BasicTypeEnum::IntType(ctx.i32_type()); let len_type = BasicTypeEnum::IntType(ptr_int(ctx, ptr_bytes));
ctx.struct_type(&[ptr_type_enum, u32_type, u32_type], false) ctx.struct_type(&[ptr_type_enum, len_type], false)
}
pub fn ptr_int<'ctx>(ctx: &'ctx Context, ptr_bytes: u32) -> IntType<'ctx> {
match ptr_bytes {
1 => ctx.i8_type(),
2 => ctx.i16_type(),
4 => ctx.i32_type(),
8 => ctx.i64_type(),
16 => ctx.i128_type(),
_ => panic!(
"Invalid target: Roc does't support compiling to {}-bit systems.",
ptr_bytes * 8
),
}
} }

View file

@ -201,16 +201,16 @@ mod test_gen {
// Compute main_fn_type before moving subs to Env // Compute main_fn_type before moving subs to Env
let layout = Layout::from_content(&arena, content, &subs, POINTER_SIZE) let layout = Layout::from_content(&arena, content, &subs, POINTER_SIZE)
.unwrap_or_else(|err| panic!("Code gen error in test: could not convert to layout. Err was {:?} and Subs were {:?}", err, subs)); .unwrap_or_else(|err| panic!("Code gen error in test: could not convert to layout. Err was {:?} and Subs were {:?}", err, subs));
let main_fn_type = basic_type_from_layout(&arena, &context, &layout)
.fn_type(&[], false);
let main_fn_name = "$Test.main";
let execution_engine = let execution_engine =
module module
.create_jit_execution_engine(OptimizationLevel::None) .create_jit_execution_engine(OptimizationLevel::None)
.expect("Error creating JIT execution engine for test"); .expect("Error creating JIT execution engine for test");
let pointer_bytes = execution_engine.get_target_data().get_pointer_byte_size(None); let ptr_bytes = execution_engine.get_target_data().get_pointer_byte_size(None);
let main_fn_type = basic_type_from_layout(&arena, &context, &layout, ptr_bytes)
.fn_type(&[], false);
let main_fn_name = "$Test.main";
// Compile and add all the Procs before adding main // Compile and add all the Procs before adding main
let mut env = roc_gen::llvm::build::Env { let mut env = roc_gen::llvm::build::Env {
@ -219,7 +219,7 @@ mod test_gen {
context: &context, context: &context,
interns, interns,
module: arena.alloc(module), module: arena.alloc(module),
pointer_bytes ptr_bytes
}; };
let mut procs = Procs::default(); let mut procs = Procs::default();
let mut ident_ids = env.interns.all_ident_ids.remove(&home).unwrap(); let mut ident_ids = env.interns.all_ident_ids.remove(&home).unwrap();
@ -338,16 +338,16 @@ mod test_gen {
// Compute main_fn_type before moving subs to Env // Compute main_fn_type before moving subs to Env
let layout = Layout::from_content(&arena, content, &subs, POINTER_SIZE) let layout = Layout::from_content(&arena, content, &subs, POINTER_SIZE)
.unwrap_or_else(|err| panic!("Code gen error in test: could not convert to layout. Err was {:?} and Subs were {:?}", err, subs)); .unwrap_or_else(|err| panic!("Code gen error in test: could not convert to layout. Err was {:?} and Subs were {:?}", err, subs));
let main_fn_type = basic_type_from_layout(&arena, &context, &layout)
.fn_type(&[], false);
let main_fn_name = "$Test.main";
let execution_engine = let execution_engine =
module module
.create_jit_execution_engine(OptimizationLevel::None) .create_jit_execution_engine(OptimizationLevel::None)
.expect("Error creating JIT execution engine for test"); .expect("Error creating JIT execution engine for test");
let pointer_bytes = execution_engine.get_target_data().get_pointer_byte_size(None); let ptr_bytes = execution_engine.get_target_data().get_pointer_byte_size(None);
let main_fn_type = basic_type_from_layout(&arena, &context, &layout, ptr_bytes)
.fn_type(&[], false);
let main_fn_name = "$Test.main";
// Compile and add all the Procs before adding main // Compile and add all the Procs before adding main
let mut env = roc_gen::llvm::build::Env { let mut env = roc_gen::llvm::build::Env {
@ -356,7 +356,7 @@ mod test_gen {
context: &context, context: &context,
interns, interns,
module: arena.alloc(module), module: arena.alloc(module),
pointer_bytes ptr_bytes
}; };
let mut procs = Procs::default(); let mut procs = Procs::default();
let mut ident_ids = env.interns.all_ident_ids.remove(&home).unwrap(); let mut ident_ids = env.interns.all_ident_ids.remove(&home).unwrap();