mirror of
https://github.com/roc-lang/roc.git
synced 2024-11-11 05:34:11 +03:00
already do some of the llvm struct_gep conversion work
This commit is contained in:
parent
0f46ea83d0
commit
bc9c813fec
@ -53,13 +53,59 @@ use std::convert::TryInto;
|
||||
use std::path::Path;
|
||||
use target_lexicon::{Architecture, OperatingSystem, Triple};
|
||||
|
||||
use super::convert::RocUnion;
|
||||
use super::convert::{struct_type_from_union_layout, RocUnion};
|
||||
use super::intrinsics::{
|
||||
add_intrinsics, LLVM_FRAME_ADDRESS, LLVM_MEMSET_I32, LLVM_MEMSET_I64, LLVM_SETJMP,
|
||||
LLVM_STACK_SAVE,
|
||||
};
|
||||
use super::lowlevel::run_higher_order_low_level;
|
||||
|
||||
pub(crate) trait BuilderExt<'ctx> {
|
||||
fn new_build_struct_gep(
|
||||
&self,
|
||||
struct_type: StructType<'ctx>,
|
||||
ptr: PointerValue<'ctx>,
|
||||
index: u32,
|
||||
name: &str,
|
||||
) -> Result<PointerValue<'ctx>, ()>;
|
||||
|
||||
fn new_build_load(
|
||||
&self,
|
||||
element_type: impl BasicType<'ctx>,
|
||||
ptr: PointerValue<'ctx>,
|
||||
name: &str,
|
||||
) -> BasicValueEnum<'ctx>;
|
||||
}
|
||||
|
||||
impl<'ctx> BuilderExt<'ctx> for Builder<'ctx> {
|
||||
fn new_build_struct_gep(
|
||||
&self,
|
||||
struct_type: StructType<'ctx>,
|
||||
ptr: PointerValue<'ctx>,
|
||||
index: u32,
|
||||
name: &str,
|
||||
) -> Result<PointerValue<'ctx>, ()> {
|
||||
assert_eq!(
|
||||
ptr.get_type().get_element_type().into_struct_type(),
|
||||
struct_type
|
||||
);
|
||||
self.build_struct_gep(ptr, index, name)
|
||||
}
|
||||
|
||||
fn new_build_load(
|
||||
&self,
|
||||
element_type: impl BasicType<'ctx>,
|
||||
ptr: PointerValue<'ctx>,
|
||||
name: &str,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
assert_eq!(
|
||||
ptr.get_type().get_element_type(),
|
||||
element_type.as_any_type_enum()
|
||||
);
|
||||
self.build_load(ptr, name)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn print_fn_verification_output() -> bool {
|
||||
dbg_do!(ROC_PRINT_LLVM_FN_VERIFICATION, {
|
||||
@ -977,7 +1023,7 @@ fn struct_pointer_from_fields<'a, 'ctx, 'env, I>(
|
||||
for (index, (field_layout, field_value)) in values {
|
||||
let field_ptr = env
|
||||
.builder
|
||||
.build_struct_gep(struct_ptr, index as u32, "field_struct_gep")
|
||||
.new_build_struct_gep(struct_type, struct_ptr, index as u32, "field_struct_gep")
|
||||
.unwrap();
|
||||
|
||||
store_roc_value(env, field_layout, field_ptr, field_value);
|
||||
@ -1172,7 +1218,8 @@ pub fn build_exp_expr<'a, 'ctx, 'env>(
|
||||
|
||||
let ptr = env
|
||||
.builder
|
||||
.build_struct_gep(
|
||||
.new_build_struct_gep(
|
||||
struct_type.into_struct_type(),
|
||||
cast_argument,
|
||||
*index as u32,
|
||||
env.arena.alloc(format!("non_nullable_unwrapped_{}", index)),
|
||||
@ -1202,7 +1249,7 @@ pub fn build_exp_expr<'a, 'ctx, 'env>(
|
||||
union_layout,
|
||||
} => {
|
||||
// cast the argument bytes into the desired shape for this tag
|
||||
let (argument, _structure_layout) = load_symbol_and_layout(scope, structure);
|
||||
let (argument, structure_layout) = load_symbol_and_layout(scope, structure);
|
||||
|
||||
match union_layout {
|
||||
UnionLayout::NonRecursive(tag_layouts) => {
|
||||
@ -1215,7 +1262,8 @@ pub fn build_exp_expr<'a, 'ctx, 'env>(
|
||||
|
||||
let opaque_data_ptr = env
|
||||
.builder
|
||||
.build_struct_gep(
|
||||
.new_build_struct_gep(
|
||||
basic_type_from_layout(env, structure_layout).into_struct_type(),
|
||||
argument.into_pointer_value(),
|
||||
RocUnion::TAG_DATA_INDEX,
|
||||
"get_opaque_data_ptr",
|
||||
@ -1230,7 +1278,12 @@ pub fn build_exp_expr<'a, 'ctx, 'env>(
|
||||
|
||||
let element_ptr = env
|
||||
.builder
|
||||
.build_struct_gep(data_ptr, *index as _, "get_opaque_data_ptr")
|
||||
.new_build_struct_gep(
|
||||
struct_type.into_struct_type(),
|
||||
data_ptr,
|
||||
*index as _,
|
||||
"get_opaque_data_ptr",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
load_roc_value(
|
||||
@ -1336,13 +1389,20 @@ fn build_wrapped_tag<'a, 'ctx, 'env>(
|
||||
|
||||
let (field_types, field_values) = build_tag_fields(env, scope, tag_field_layouts, arguments);
|
||||
|
||||
let union_struct_type = struct_type_from_union_layout(env, union_layout);
|
||||
|
||||
// Create the struct_type
|
||||
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.target_info) {
|
||||
let tag_id_ptr = builder
|
||||
.build_struct_gep(raw_data_ptr, RocUnion::TAG_ID_INDEX, "tag_id_index")
|
||||
.new_build_struct_gep(
|
||||
union_struct_type,
|
||||
raw_data_ptr,
|
||||
RocUnion::TAG_ID_INDEX,
|
||||
"tag_id_index",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let tag_id_type = basic_type_from_layout(env, &tag_id_layout).into_int_type();
|
||||
@ -1351,7 +1411,12 @@ fn build_wrapped_tag<'a, 'ctx, 'env>(
|
||||
.build_store(tag_id_ptr, tag_id_type.const_int(tag_id as u64, false));
|
||||
|
||||
let opaque_struct_ptr = builder
|
||||
.build_struct_gep(raw_data_ptr, RocUnion::TAG_DATA_INDEX, "tag_data_index")
|
||||
.new_build_struct_gep(
|
||||
union_struct_type,
|
||||
raw_data_ptr,
|
||||
RocUnion::TAG_DATA_INDEX,
|
||||
"tag_data_index",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
struct_pointer_from_fields(
|
||||
@ -1757,18 +1822,20 @@ pub fn get_tag_id<'a, 'ctx, 'env>(
|
||||
let tag_id_layout = union_layout.tag_id_layout();
|
||||
let tag_id_int_type = basic_type_from_layout(env, &tag_id_layout).into_int_type();
|
||||
|
||||
let union_struct_type = struct_type_from_union_layout(env, union_layout);
|
||||
|
||||
match union_layout {
|
||||
UnionLayout::NonRecursive(_) => {
|
||||
debug_assert!(argument.is_pointer_value(), "{:?}", argument);
|
||||
|
||||
let argument_ptr = argument.into_pointer_value();
|
||||
get_tag_id_wrapped(env, argument_ptr)
|
||||
get_tag_id_wrapped(env, union_struct_type, argument_ptr)
|
||||
}
|
||||
UnionLayout::Recursive(_) => {
|
||||
let argument_ptr = argument.into_pointer_value();
|
||||
|
||||
if union_layout.stores_tag_id_as_data(env.target_info) {
|
||||
get_tag_id_wrapped(env, argument_ptr)
|
||||
get_tag_id_wrapped(env, union_struct_type, argument_ptr)
|
||||
} else {
|
||||
tag_pointer_read_tag_id(env, argument_ptr)
|
||||
}
|
||||
@ -1799,7 +1866,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.target_info) {
|
||||
get_tag_id_wrapped(env, argument_ptr)
|
||||
get_tag_id_wrapped(env, union_struct_type, argument_ptr)
|
||||
} else {
|
||||
tag_pointer_read_tag_id(env, argument_ptr)
|
||||
};
|
||||
@ -1844,7 +1911,7 @@ fn lookup_at_index_ptr<'a, 'ctx, 'env>(
|
||||
);
|
||||
|
||||
let elem_ptr = builder
|
||||
.build_struct_gep(ptr, index as u32, "at_index_struct_gep")
|
||||
.new_build_struct_gep(struct_type, ptr, index as u32, "at_index_struct_gep")
|
||||
.unwrap();
|
||||
|
||||
let field_layout = field_layouts[index];
|
||||
@ -1878,7 +1945,7 @@ fn lookup_at_index_ptr2<'a, 'ctx, 'env>(
|
||||
let builder = env.builder;
|
||||
|
||||
let struct_layout = Layout::struct_no_name_order(field_layouts);
|
||||
let struct_type = basic_type_from_layout(env, &struct_layout);
|
||||
let struct_type = basic_type_from_layout(env, &struct_layout).into_struct_type();
|
||||
|
||||
let data_ptr = env.builder.build_pointer_cast(
|
||||
value,
|
||||
@ -1887,7 +1954,12 @@ fn lookup_at_index_ptr2<'a, 'ctx, 'env>(
|
||||
);
|
||||
|
||||
let elem_ptr = builder
|
||||
.build_struct_gep(data_ptr, index as u32, "at_index_struct_gep_data")
|
||||
.new_build_struct_gep(
|
||||
struct_type,
|
||||
data_ptr,
|
||||
index as u32,
|
||||
"at_index_struct_gep_data",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let field_layout = field_layouts[index];
|
||||
@ -2940,11 +3012,17 @@ 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: &Env<'a, 'ctx, 'env>,
|
||||
union_struct_type: StructType<'ctx>,
|
||||
from_value: PointerValue<'ctx>,
|
||||
) -> IntValue<'ctx> {
|
||||
let tag_id_ptr = env
|
||||
.builder
|
||||
.build_struct_gep(from_value, RocUnion::TAG_ID_INDEX, "tag_id_ptr")
|
||||
.new_build_struct_gep(
|
||||
union_struct_type,
|
||||
from_value,
|
||||
RocUnion::TAG_ID_INDEX,
|
||||
"tag_id_ptr",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
env.builder
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::llvm::build::Env;
|
||||
use crate::llvm::build::{BuilderExt, Env};
|
||||
use bumpalo::collections::Vec;
|
||||
use inkwell::context::Context;
|
||||
use inkwell::types::{BasicType, BasicTypeEnum, FloatType, IntType, StructType};
|
||||
@ -53,18 +53,16 @@ pub fn basic_type_from_layout<'a, 'ctx, 'env>(
|
||||
}
|
||||
}
|
||||
|
||||
pub fn basic_type_from_union_layout<'a, 'ctx, 'env>(
|
||||
pub fn struct_type_from_union_layout<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
union_layout: &UnionLayout<'_>,
|
||||
) -> BasicTypeEnum<'ctx> {
|
||||
) -> StructType<'ctx> {
|
||||
use UnionLayout::*;
|
||||
|
||||
match union_layout {
|
||||
NonRecursive(tags) => {
|
||||
//
|
||||
RocUnion::tagged_from_slices(env.layout_interner, env.context, tags, env.target_info)
|
||||
.struct_type()
|
||||
.into()
|
||||
}
|
||||
Recursive(tags)
|
||||
| NullableWrapped {
|
||||
@ -78,8 +76,6 @@ pub fn basic_type_from_union_layout<'a, 'ctx, 'env>(
|
||||
env.target_info,
|
||||
)
|
||||
.struct_type()
|
||||
.ptr_type(AddressSpace::Generic)
|
||||
.into()
|
||||
} else {
|
||||
RocUnion::untagged_from_slices(
|
||||
env.layout_interner,
|
||||
@ -88,8 +84,6 @@ pub fn basic_type_from_union_layout<'a, 'ctx, 'env>(
|
||||
env.target_info,
|
||||
)
|
||||
.struct_type()
|
||||
.ptr_type(AddressSpace::Generic)
|
||||
.into()
|
||||
}
|
||||
}
|
||||
NullableUnwrapped { other_fields, .. } => RocUnion::untagged_from_slices(
|
||||
@ -98,18 +92,31 @@ pub fn basic_type_from_union_layout<'a, 'ctx, 'env>(
|
||||
&[other_fields],
|
||||
env.target_info,
|
||||
)
|
||||
.struct_type()
|
||||
.ptr_type(AddressSpace::Generic)
|
||||
.into(),
|
||||
.struct_type(),
|
||||
NonNullableUnwrapped(fields) => RocUnion::untagged_from_slices(
|
||||
env.layout_interner,
|
||||
env.context,
|
||||
&[fields],
|
||||
env.target_info,
|
||||
)
|
||||
.struct_type()
|
||||
.ptr_type(AddressSpace::Generic)
|
||||
.into(),
|
||||
.struct_type(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn basic_type_from_union_layout<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
union_layout: &UnionLayout<'_>,
|
||||
) -> BasicTypeEnum<'ctx> {
|
||||
use UnionLayout::*;
|
||||
|
||||
let struct_type = struct_type_from_union_layout(env, union_layout);
|
||||
|
||||
match union_layout {
|
||||
NonRecursive(_) => struct_type.into(),
|
||||
Recursive(_)
|
||||
| NonNullableUnwrapped(_)
|
||||
| NullableWrapped { .. }
|
||||
| NullableUnwrapped { .. } => struct_type.ptr_type(AddressSpace::Generic).into(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -363,7 +370,12 @@ impl<'ctx> RocUnion<'ctx> {
|
||||
|
||||
let data_buffer = env
|
||||
.builder
|
||||
.build_struct_gep(tag_alloca, Self::TAG_DATA_INDEX, "data_buffer")
|
||||
.new_build_struct_gep(
|
||||
self.struct_type(),
|
||||
tag_alloca,
|
||||
Self::TAG_DATA_INDEX,
|
||||
"data_buffer",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let cast_pointer = env.builder.build_pointer_cast(
|
||||
@ -389,7 +401,12 @@ impl<'ctx> RocUnion<'ctx> {
|
||||
|
||||
let tag_id_ptr = env
|
||||
.builder
|
||||
.build_struct_gep(tag_alloca, Self::TAG_ID_INDEX, "tag_id_ptr")
|
||||
.new_build_struct_gep(
|
||||
self.struct_type(),
|
||||
tag_alloca,
|
||||
Self::TAG_ID_INDEX,
|
||||
"tag_id_ptr",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let tag_id = tag_id_type.const_int(tag_id as u64, false);
|
||||
|
@ -14,6 +14,7 @@ use roc_mono::ir::LookupType;
|
||||
use roc_mono::layout::{Builtin, Layout, LayoutIds, UnionLayout};
|
||||
use roc_region::all::Region;
|
||||
|
||||
use super::build::BuilderExt;
|
||||
use super::build::{
|
||||
add_func, load_roc_value, load_symbol_and_layout, use_roc_value, FunctionSpec, LlvmBackendMode,
|
||||
Scope, WhenRecursive,
|
||||
@ -529,7 +530,12 @@ fn load_tag_data<'a, 'ctx, 'env>(
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
let raw_data_ptr = env
|
||||
.builder
|
||||
.build_struct_gep(tag_value, RocUnion::TAG_DATA_INDEX, "tag_data")
|
||||
.new_build_struct_gep(
|
||||
tag_type.into_struct_type(),
|
||||
tag_value,
|
||||
RocUnion::TAG_DATA_INDEX,
|
||||
"tag_data",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let data_ptr = env.builder.build_pointer_cast(
|
||||
|
@ -1,5 +1,6 @@
|
||||
use crate::debug_info_init;
|
||||
use crate::llvm::bitcode::call_void_bitcode_fn;
|
||||
use crate::llvm::build::BuilderExt;
|
||||
use crate::llvm::build::{
|
||||
add_func, cast_basic_basic, get_tag_id, tag_pointer_clear_tag_id, use_roc_value, Env,
|
||||
WhenRecursive, FAST_CALL_CONV,
|
||||
@ -541,7 +542,7 @@ fn modify_refcount_layout_build_function<'a, 'ctx, 'env>(
|
||||
|
||||
NonRecursive(tags) => {
|
||||
let function =
|
||||
modify_refcount_union(env, layout_ids, mode, when_recursive, tags);
|
||||
modify_refcount_nonrecursive(env, layout_ids, mode, when_recursive, tags);
|
||||
|
||||
Some(function)
|
||||
}
|
||||
@ -1226,7 +1227,12 @@ fn build_rec_union_recursive_decrement<'a, 'ctx, 'env>(
|
||||
// this field has type `*i64`, but is really a pointer to the data we want
|
||||
let elem_pointer = env
|
||||
.builder
|
||||
.build_struct_gep(struct_ptr, i as u32, "gep_recursive_pointer")
|
||||
.new_build_struct_gep(
|
||||
wrapper_type.into_struct_type(),
|
||||
struct_ptr,
|
||||
i as u32,
|
||||
"gep_recursive_pointer",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let ptr_as_i64_ptr = env
|
||||
@ -1243,7 +1249,12 @@ fn build_rec_union_recursive_decrement<'a, 'ctx, 'env>(
|
||||
} else if field_layout.contains_refcounted(env.layout_interner) {
|
||||
let elem_pointer = env
|
||||
.builder
|
||||
.build_struct_gep(struct_ptr, i as u32, "gep_recursive_pointer")
|
||||
.new_build_struct_gep(
|
||||
wrapper_type.into_struct_type(),
|
||||
struct_ptr,
|
||||
i as u32,
|
||||
"gep_recursive_pointer",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let field =
|
||||
@ -1499,7 +1510,7 @@ fn function_name_from_mode<'a>(
|
||||
}
|
||||
}
|
||||
|
||||
fn modify_refcount_union<'a, 'ctx, 'env>(
|
||||
fn modify_refcount_nonrecursive<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
mode: Mode,
|
||||
@ -1527,7 +1538,7 @@ fn modify_refcount_union<'a, 'ctx, 'env>(
|
||||
let basic_type = argument_type_from_union_layout(env, &union_layout);
|
||||
let function_value = build_header(env, basic_type, mode, &fn_name);
|
||||
|
||||
modify_refcount_union_help(
|
||||
modify_refcount_nonrecursive_help(
|
||||
env,
|
||||
layout_ids,
|
||||
mode,
|
||||
@ -1547,7 +1558,7 @@ fn modify_refcount_union<'a, 'ctx, 'env>(
|
||||
function
|
||||
}
|
||||
|
||||
fn modify_refcount_union_help<'a, 'ctx, 'env>(
|
||||
fn modify_refcount_nonrecursive_help<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
mode: Mode,
|
||||
@ -1577,10 +1588,19 @@ fn modify_refcount_union_help<'a, 'ctx, 'env>(
|
||||
|
||||
let before_block = env.builder.get_insert_block().expect("to be in a function");
|
||||
|
||||
let union_layout = UnionLayout::NonRecursive(tags);
|
||||
let layout = Layout::Union(union_layout);
|
||||
let union_struct_type = basic_type_from_layout(env, &layout).into_struct_type();
|
||||
|
||||
// read the tag_id
|
||||
let tag_id_ptr = env
|
||||
.builder
|
||||
.build_struct_gep(arg_ptr, RocUnion::TAG_ID_INDEX, "tag_id_ptr")
|
||||
.new_build_struct_gep(
|
||||
union_struct_type,
|
||||
arg_ptr,
|
||||
RocUnion::TAG_ID_INDEX,
|
||||
"tag_id_ptr",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let tag_id = env
|
||||
@ -1611,18 +1631,24 @@ fn modify_refcount_union_help<'a, 'ctx, 'env>(
|
||||
let block = env.context.append_basic_block(parent, "tag_id_modify");
|
||||
env.builder.position_at_end(block);
|
||||
|
||||
let wrapper_type =
|
||||
let data_struct_type =
|
||||
basic_type_from_layout(env, &Layout::struct_no_name_order(field_layouts));
|
||||
|
||||
debug_assert!(wrapper_type.is_struct_type());
|
||||
debug_assert!(data_struct_type.is_struct_type());
|
||||
let data_struct_type = data_struct_type.into_struct_type();
|
||||
let opaque_tag_data_ptr = env
|
||||
.builder
|
||||
.build_struct_gep(arg_ptr, RocUnion::TAG_DATA_INDEX, "field_ptr")
|
||||
.new_build_struct_gep(
|
||||
union_struct_type,
|
||||
arg_ptr,
|
||||
RocUnion::TAG_DATA_INDEX,
|
||||
"field_ptr",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let cast_tag_data_pointer = env.builder.build_pointer_cast(
|
||||
opaque_tag_data_ptr,
|
||||
wrapper_type.ptr_type(AddressSpace::Generic),
|
||||
data_struct_type.ptr_type(AddressSpace::Generic),
|
||||
"cast_to_concrete_tag",
|
||||
);
|
||||
|
||||
@ -1638,7 +1664,12 @@ fn modify_refcount_union_help<'a, 'ctx, 'env>(
|
||||
// This field is a pointer to the recursive pointer.
|
||||
let field_ptr = env
|
||||
.builder
|
||||
.build_struct_gep(cast_tag_data_pointer, i as u32, "modify_tag_field")
|
||||
.new_build_struct_gep(
|
||||
data_struct_type,
|
||||
cast_tag_data_pointer,
|
||||
i as u32,
|
||||
"modify_tag_field",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// This is the actual pointer to the recursive data.
|
||||
@ -1663,7 +1694,12 @@ fn modify_refcount_union_help<'a, 'ctx, 'env>(
|
||||
} else if field_layout.contains_refcounted(env.layout_interner) {
|
||||
let field_ptr = env
|
||||
.builder
|
||||
.build_struct_gep(cast_tag_data_pointer, i as u32, "modify_tag_field")
|
||||
.new_build_struct_gep(
|
||||
data_struct_type,
|
||||
cast_tag_data_pointer,
|
||||
i as u32,
|
||||
"modify_tag_field",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let field_value =
|
||||
|
Loading…
Reference in New Issue
Block a user