move all allocas to the entry block

This commit is contained in:
Brendan Hansknecht 2024-07-20 19:17:11 -07:00
parent 70fa3ecdc2
commit ee7f1e39c7
No known key found for this signature in database
GPG key ID: 0EA784685083E75B
8 changed files with 116 additions and 230 deletions

View file

@ -936,9 +936,7 @@ impl<'a, 'ctx, 'env> Env<'a, 'ctx, 'env> {
match env.target.ptr_width() {
PtrWidth::Bytes4 => {
// we need to pass the string by reference, but we currently hold the value.
let alloca = env
.builder
.new_build_alloca(string.get_type(), "alloca_string");
let alloca = create_entry_block_alloca(env, string.get_type(), "alloca_string");
env.builder.new_build_store(alloca, string);
alloca.into()
}
@ -1345,7 +1343,6 @@ fn float_with_precision<'ctx>(
pub fn build_exp_literal<'a, 'ctx>(
env: &Env<'a, 'ctx, '_>,
layout_interner: &STLayoutInterner<'a>,
parent: FunctionValue<'ctx>,
layout: InLayout<'_>,
literal: &roc_mono::ir::Literal<'a>,
) -> BasicValueEnum<'ctx> {
@ -1382,18 +1379,14 @@ pub fn build_exp_literal<'a, 'ctx>(
}
Bool(b) => env.context.bool_type().const_int(*b as u64, false).into(),
Byte(b) => env.context.i8_type().const_int(*b as u64, false).into(),
Str(str_literal) => build_string_literal(env, parent, str_literal),
Str(str_literal) => build_string_literal(env, str_literal),
}
}
fn build_string_literal<'ctx>(
env: &Env<'_, 'ctx, '_>,
parent: FunctionValue<'ctx>,
str_literal: &str,
) -> BasicValueEnum<'ctx> {
fn build_string_literal<'ctx>(env: &Env<'_, 'ctx, '_>, str_literal: &str) -> BasicValueEnum<'ctx> {
if str_literal.len() < env.small_str_bytes() as usize {
match env.small_str_bytes() {
24 => small_str_ptr_width_8(env, parent, str_literal).into(),
24 => small_str_ptr_width_8(env, str_literal).into(),
12 => small_str_ptr_width_4(env, str_literal).into(),
_ => unreachable!("incorrect small_str_bytes"),
}
@ -1401,7 +1394,7 @@ fn build_string_literal<'ctx>(
let ptr = define_global_str_literal_ptr(env, str_literal);
let number_of_elements = env.ptr_int().const_int(str_literal.len() as u64, false);
let alloca = const_str_alloca_ptr(env, parent, ptr, number_of_elements, number_of_elements);
let alloca = const_str_alloca_ptr(env, ptr, number_of_elements, number_of_elements);
match env.target.ptr_width() {
PtrWidth::Bytes4 => {
@ -1415,7 +1408,6 @@ fn build_string_literal<'ctx>(
fn const_str_alloca_ptr<'ctx>(
env: &Env<'_, 'ctx, '_>,
parent: FunctionValue<'ctx>,
ptr: PointerValue<'ctx>,
len: IntValue<'ctx>,
cap: IntValue<'ctx>,
@ -1424,18 +1416,14 @@ fn const_str_alloca_ptr<'ctx>(
let value = typ.const_named_struct(&[ptr.into(), len.into(), cap.into()]);
let alloca = create_entry_block_alloca(env, parent, typ.into(), "const_str_store");
let alloca = create_entry_block_alloca(env, typ, "const_str_store");
env.builder.new_build_store(alloca, value);
alloca
}
fn small_str_ptr_width_8<'ctx>(
env: &Env<'_, 'ctx, '_>,
parent: FunctionValue<'ctx>,
str_literal: &str,
) -> PointerValue<'ctx> {
fn small_str_ptr_width_8<'ctx>(env: &Env<'_, 'ctx, '_>, str_literal: &str) -> PointerValue<'ctx> {
debug_assert_eq!(env.target.ptr_width() as u8, 8);
let mut array = [0u8; 24];
@ -1456,7 +1444,7 @@ fn small_str_ptr_width_8<'ctx>(
let ptr_type = env.context.i8_type().ptr_type(address_space);
let ptr = env.builder.new_build_int_to_ptr(ptr, ptr_type, "to_u8_ptr");
const_str_alloca_ptr(env, parent, ptr, len, cap)
const_str_alloca_ptr(env, ptr, len, cap)
}
fn small_str_ptr_width_4<'ctx>(env: &Env<'_, 'ctx, '_>, str_literal: &str) -> StructValue<'ctx> {
@ -1653,7 +1641,7 @@ pub(crate) fn build_exp_expr<'a, 'ctx>(
use roc_mono::ir::Expr::*;
match expr {
Literal(literal) => build_exp_literal(env, layout_interner, parent, layout, literal),
Literal(literal) => build_exp_literal(env, layout_interner, layout, literal),
NullPointer => {
let basic_type =
basic_type_from_layout(env, layout_interner, layout_interner.get_repr(layout));
@ -1918,7 +1906,7 @@ pub(crate) fn build_exp_expr<'a, 'ctx>(
EmptyArray => empty_polymorphic_list(env),
Array { elem_layout, elems } => {
list_literal(env, layout_interner, parent, scope, *elem_layout, elems)
list_literal(env, layout_interner, scope, *elem_layout, elems)
}
RuntimeErrorFunction(_) => todo!(),
@ -2204,7 +2192,7 @@ pub(crate) fn build_exp_expr<'a, 'ctx>(
layout_interner,
layout_interner.get_repr(*element_layout),
);
let ptr = entry_block_alloca_zerofill(env, element_type, "stack_value");
let ptr = create_entry_block_alloca(env, element_type, "stack_value");
if let Some(initializer) = initializer {
env.builder
@ -2295,21 +2283,6 @@ fn build_wrapped_tag<'a, 'ctx>(
}
}
pub fn entry_block_alloca_zerofill<'ctx>(
env: &Env<'_, 'ctx, '_>,
basic_type: BasicTypeEnum<'ctx>,
name: &str,
) -> PointerValue<'ctx> {
let parent = env
.builder
.get_insert_block()
.unwrap()
.get_parent()
.unwrap();
create_entry_block_alloca(env, parent, basic_type, name)
}
fn build_tag_field_value<'a, 'ctx>(
env: &Env<'a, 'ctx, '_>,
layout_interner: &STLayoutInterner<'a>,
@ -2395,10 +2368,7 @@ fn build_tag<'a, 'ctx>(
let roc_union = RocUnion::tagged_from_slices(layout_interner, env.context, tags);
let tag_alloca = env
.builder
.new_build_alloca(roc_union.struct_type(), "tag_alloca");
let tag_alloca = create_entry_block_alloca(env, roc_union.struct_type(), "tag_alloca");
roc_union.write_struct_data(
env,
layout_interner,
@ -2692,8 +2662,6 @@ pub fn get_tag_id<'a, 'ctx>(
union_layout: &UnionLayout<'a>,
argument: BasicValueEnum<'ctx>,
) -> IntValue<'ctx> {
let builder = env.builder;
let tag_id_layout = union_layout.tag_id_layout();
let tag_id_int_type = basic_type_from_layout(
env,
@ -2728,7 +2696,7 @@ pub fn get_tag_id<'a, 'ctx>(
let else_block = ctx.append_basic_block(parent, "else");
let cont_block = ctx.append_basic_block(parent, "cont");
let result = builder.new_build_alloca(tag_id_int_type, "result");
let result = create_entry_block_alloca(env, tag_id_int_type, "result");
env.builder
.new_build_conditional_branch(is_null, then_block, else_block);
@ -2801,7 +2769,7 @@ fn lookup_at_index_ptr<'a, 'ctx>(
// A recursive pointer in the loaded structure is stored as a `i64*`, but the loaded layout
// might want a more precise structure. As such, cast it to the refined type if needed.
cast_if_necessary_for_opaque_recursive_pointers(env.builder, result, target_loaded_type)
cast_if_necessary_for_opaque_recursive_pointers(env, result, target_loaded_type)
}
fn union_field_ptr_at_index_help<'a, 'ctx>(
@ -2858,8 +2826,7 @@ fn union_field_ptr_at_index<'a, 'ctx>(
// might want a more precise structure. As such, cast it to the refined type if needed.
let from_value: BasicValueEnum = result.into();
let to_type: BasicTypeEnum = target_loaded_type;
cast_if_necessary_for_opaque_recursive_pointers(env.builder, from_value, to_type)
.into_pointer_value()
cast_if_necessary_for_opaque_recursive_pointers(env, from_value, to_type).into_pointer_value()
}
fn reserve_with_refcount_union_as_block_of_memory<'a, 'ctx>(
@ -2932,7 +2899,6 @@ pub fn allocate_with_refcount_help<'a, 'ctx, 'env>(
fn list_literal<'a, 'ctx>(
env: &Env<'a, 'ctx, '_>,
layout_interner: &STLayoutInterner<'a>,
parent: FunctionValue<'ctx>,
scope: &Scope<'a, 'ctx>,
element_layout: InLayout<'a>,
elems: &[ListLiteralElement],
@ -2989,13 +2955,7 @@ fn list_literal<'a, 'ctx>(
for (index, element) in elems.iter().enumerate() {
match element {
ListLiteralElement::Literal(literal) => {
let val = build_exp_literal(
env,
layout_interner,
parent,
element_layout,
literal,
);
let val = build_exp_literal(env, layout_interner, element_layout, literal);
global_elements.push(val.into_int_value());
}
ListLiteralElement::Symbol(symbol) => {
@ -3086,7 +3046,7 @@ fn list_literal<'a, 'ctx>(
for (index, element) in elems.iter().enumerate() {
let val = match element {
ListLiteralElement::Literal(literal) => {
build_exp_literal(env, layout_interner, parent, element_layout, literal)
build_exp_literal(env, layout_interner, element_layout, literal)
}
ListLiteralElement::Symbol(symbol) => scope.load_symbol(symbol),
};
@ -3118,7 +3078,7 @@ pub fn load_roc_value<'a, 'ctx>(
let basic_type = basic_type_from_layout(env, layout_interner, layout);
if layout.is_passed_by_reference(layout_interner) {
let alloca = entry_block_alloca_zerofill(env, basic_type, name);
let alloca = create_entry_block_alloca(env, basic_type, name);
store_roc_value(env, layout_interner, layout, alloca, source.into());
@ -3136,7 +3096,7 @@ pub fn use_roc_value<'a, 'ctx>(
name: &str,
) -> BasicValueEnum<'ctx> {
if layout.is_passed_by_reference(layout_interner) {
let alloca = entry_block_alloca_zerofill(
let alloca = create_entry_block_alloca(
env,
basic_type_from_layout(env, layout_interner, layout),
name,
@ -3576,8 +3536,8 @@ pub(crate) fn build_exp_stmt<'a, 'ctx>(
remainder,
} => {
if env.mode.runs_expects() {
let location = build_string_literal(env, parent, source_location);
let source = build_string_literal(env, parent, source);
let location = build_string_literal(env, source_location);
let source = build_string_literal(env, source);
let message = scope.load_symbol(symbol);
env.call_dbg(env, location, source, message);
}
@ -3644,7 +3604,7 @@ pub(crate) fn build_exp_stmt<'a, 'ctx>(
}
roc_target::PtrWidth::Bytes4 => {
// temporary WASM implementation
throw_internal_exception(env, parent, "An expectation failed!");
throw_internal_exception(env, "An expectation failed!");
}
}
} else {
@ -3712,7 +3672,7 @@ pub(crate) fn build_exp_stmt<'a, 'ctx>(
}
roc_target::PtrWidth::Bytes4 => {
// temporary WASM implementation
throw_internal_exception(env, parent, "An expectation failed!");
throw_internal_exception(env, "An expectation failed!");
}
}
} else {
@ -3844,7 +3804,7 @@ fn equivalent_type_constructors(t1: &BasicTypeEnum, t2: &BasicTypeEnum) -> bool
/// This will no longer be necessary and should be removed after we employ opaque pointers from
/// LLVM.
pub fn cast_if_necessary_for_opaque_recursive_pointers<'ctx>(
builder: &Builder<'ctx>,
env: &Env<'_, 'ctx, '_>,
from_value: BasicValueEnum<'ctx>,
to_type: BasicTypeEnum<'ctx>,
) -> BasicValueEnum<'ctx> {
@ -3853,7 +3813,7 @@ pub fn cast_if_necessary_for_opaque_recursive_pointers<'ctx>(
&& equivalent_type_constructors(&from_value.get_type(), &to_type)
{
complex_bitcast(
builder,
env,
from_value,
to_type,
"bitcast_for_opaque_recursive_pointer",
@ -3865,39 +3825,33 @@ pub fn cast_if_necessary_for_opaque_recursive_pointers<'ctx>(
/// Cast a value to another value of the same (or smaller?) size
pub fn cast_basic_basic<'ctx>(
builder: &Builder<'ctx>,
env: &Env<'_, 'ctx, '_>,
from_value: BasicValueEnum<'ctx>,
to_type: BasicTypeEnum<'ctx>,
) -> BasicValueEnum<'ctx> {
complex_bitcast(builder, from_value, to_type, "cast_basic_basic")
complex_bitcast(env, from_value, to_type, "cast_basic_basic")
}
pub fn complex_bitcast_struct_struct<'ctx>(
builder: &Builder<'ctx>,
env: &Env<'_, 'ctx, '_>,
from_value: StructValue<'ctx>,
to_type: StructType<'ctx>,
name: &str,
) -> StructValue<'ctx> {
complex_bitcast(builder, from_value.into(), to_type.into(), name).into_struct_value()
complex_bitcast(env, from_value.into(), to_type.into(), name).into_struct_value()
}
pub fn cast_block_of_memory_to_tag<'ctx>(
builder: &Builder<'ctx>,
env: &Env<'_, 'ctx, '_>,
from_value: StructValue<'ctx>,
to_type: BasicTypeEnum<'ctx>,
) -> StructValue<'ctx> {
complex_bitcast(
builder,
from_value.into(),
to_type,
"block_of_memory_to_tag",
)
.into_struct_value()
complex_bitcast(env, from_value.into(), to_type, "block_of_memory_to_tag").into_struct_value()
}
/// Cast a value to another value of the same (or smaller?) size
pub fn complex_bitcast<'ctx>(
builder: &Builder<'ctx>,
env: &Env<'_, 'ctx, '_>,
from_value: BasicValueEnum<'ctx>,
to_type: BasicTypeEnum<'ctx>,
name: &str,
@ -3908,7 +3862,8 @@ pub fn complex_bitcast<'ctx>(
// we can't use the more straightforward bitcast in all cases
// it seems like a bitcast only works on integers and pointers
// and crucially does not work not on arrays
return builder
return env
.builder
.new_build_pointer_cast(
from_value.into_pointer_value(),
to_type.into_pointer_type(),
@ -3917,7 +3872,7 @@ pub fn complex_bitcast<'ctx>(
.into();
}
complex_bitcast_from_bigger_than_to(builder, from_value, to_type, name)
complex_bitcast_from_bigger_than_to(env, from_value, to_type, name)
}
/// Check the size of the input and output types. Pretending we have more bytes at a pointer than
@ -3965,14 +3920,14 @@ pub fn complex_bitcast_check_size<'ctx>(
let then_answer = {
env.builder.position_at_end(then_block);
let result = complex_bitcast_from_bigger_than_to(env.builder, from_value, to_type, name);
let result = complex_bitcast_from_bigger_than_to(env, from_value, to_type, name);
env.builder.new_build_unconditional_branch(cont_block);
result
};
let else_answer = {
env.builder.position_at_end(else_block);
let result = complex_bitcast_to_bigger_than_from(env.builder, from_value, to_type, name);
let result = complex_bitcast_to_bigger_than_from(env, from_value, to_type, name);
env.builder.new_build_unconditional_branch(cont_block);
result
};
@ -3987,13 +3942,15 @@ pub fn complex_bitcast_check_size<'ctx>(
}
fn complex_bitcast_from_bigger_than_to<'ctx>(
builder: &Builder<'ctx>,
env: &Env<'_, 'ctx, '_>,
from_value: BasicValueEnum<'ctx>,
to_type: BasicTypeEnum<'ctx>,
name: &str,
) -> BasicValueEnum<'ctx> {
let builder = env.builder;
// store the value in memory
let argument_pointer = builder.new_build_alloca(from_value.get_type(), "cast_alloca");
let argument_pointer = create_entry_block_alloca(env, from_value.get_type(), "cast_alloca");
builder.new_build_store(argument_pointer, from_value);
// then read it back as a different type
@ -4007,15 +3964,16 @@ fn complex_bitcast_from_bigger_than_to<'ctx>(
}
fn complex_bitcast_to_bigger_than_from<'ctx>(
builder: &Builder<'ctx>,
env: &Env<'_, 'ctx, '_>,
from_value: BasicValueEnum<'ctx>,
to_type: BasicTypeEnum<'ctx>,
name: &str,
) -> BasicValueEnum<'ctx> {
let builder = env.builder;
// reserve space in memory with the return type. This way, if the return type is bigger
// than the input type, we don't access invalid memory when later taking a pointer to
// the cast value
let storage = builder.new_build_alloca(to_type, "cast_alloca");
let storage = create_entry_block_alloca(env, to_type, "cast_alloca");
// then cast the pointer to our desired type
let from_type_pointer = builder.new_build_pointer_cast(
@ -4035,7 +3993,7 @@ fn complex_bitcast_to_bigger_than_from<'ctx>(
/// get the tag id out of a pointer to a wrapped (i.e. stores the tag id at runtime) layout
fn get_tag_id_wrapped<'a, 'ctx>(
env: &Env<'a, 'ctx, '_>,
env: &Env<'_, 'ctx, '_>,
layout_interner: &STLayoutInterner<'a>,
union_layout: UnionLayout<'a>,
from_value: PointerValue<'ctx>,
@ -4308,12 +4266,18 @@ fn build_switch_ir<'a, 'ctx>(
}
/// Creates a new stack allocation instruction in the entry block of the function.
pub fn create_entry_block_alloca<'ctx>(
pub fn create_entry_block_alloca<'ctx, T: BasicType<'ctx>>(
env: &Env<'_, 'ctx, '_>,
parent: FunctionValue<'_>,
basic_type: BasicTypeEnum<'ctx>,
basic_type: T,
name: &str,
) -> PointerValue<'ctx> {
let parent = env
.builder
.get_insert_block()
.expect("builder to be in a block")
.get_parent()
.expect("block to be in a function");
let builder = env.context.create_builder();
let entry = parent.get_first_basic_block().unwrap();
@ -5212,7 +5176,7 @@ fn set_jump_and_catch_long_jump<'a, 'ctx>(
RocReturn::from_layout(layout_interner, layout)
};
let call_result_type = roc_call_result_type(env, return_type.as_basic_type_enum());
let result_alloca = builder.new_build_alloca(call_result_type, "result");
let result_alloca = create_entry_block_alloca(env, call_result_type, "result");
let then_block = context.append_basic_block(parent, "then_block");
let catch_block = context.append_basic_block(parent, "catch_block");
@ -6392,7 +6356,7 @@ fn call_roc_function_help<'a, 'ctx>(
arguments.pop();
let result_type = basic_type_from_layout(env, layout_interner, result_layout);
let result_alloca = env.builder.new_build_alloca(result_type, "result_value");
let result_alloca = create_entry_block_alloca(env, result_type, "result_value");
arguments.push(result_alloca.into());
@ -6410,7 +6374,7 @@ fn call_roc_function_help<'a, 'ctx>(
let mut arguments = Vec::from_iter_in(it, env.arena);
let result_type = basic_type_from_layout(env, layout_interner, result_layout);
let result_alloca = entry_block_alloca_zerofill(env, result_type, "result_value");
let result_alloca = create_entry_block_alloca(env, result_type, "result_value");
arguments.push(result_alloca.into());
@ -6494,9 +6458,7 @@ pub(crate) fn roc_function_call<'a, 'ctx>(
layout_interner.get_repr(lambda_set.runtime_representation()),
);
let closure_data_ptr = env
.builder
.new_build_alloca(closure_data_type, "closure_data_ptr");
let closure_data_ptr = create_entry_block_alloca(env, closure_data_type, "closure_data_ptr");
store_roc_value(
env,
@ -6864,7 +6826,9 @@ fn build_foreign_symbol<'a, 'ctx>(
Vec::with_capacity_in(fastcc_parameters.len() + 1, env.arena);
let return_pointer = match roc_return {
RocReturn::Return => env.builder.new_build_alloca(return_type, "return_value"),
RocReturn::Return => {
create_entry_block_alloca(env, return_type, "return_value")
}
RocReturn::ByPointer => fastcc_parameters.pop().unwrap().into_pointer_value(),
};
@ -6882,9 +6846,8 @@ fn build_foreign_symbol<'a, 'ctx>(
// we need to pass this value by-reference; put it into an alloca
// and bitcast the reference
let param_alloca = env
.builder
.new_build_alloca(param.get_type(), "param_alloca");
let param_alloca =
create_entry_block_alloca(env, param.get_type(), "param_alloca");
env.builder.new_build_store(param_alloca, param);
let as_cc_type = env.builder.new_build_pointer_cast(
@ -7042,14 +7005,10 @@ fn define_global_str_literal<'ctx>(
}
}
pub(crate) fn throw_internal_exception<'ctx>(
env: &Env<'_, 'ctx, '_>,
parent: FunctionValue<'ctx>,
message: &str,
) {
pub(crate) fn throw_internal_exception<'ctx>(env: &Env<'_, 'ctx, '_>, message: &str) {
let builder = env.builder;
let str = build_string_literal(env, parent, message);
let str = build_string_literal(env, message);
env.call_panic(env, str, CrashTag::Roc);