already do some of the llvm struct_gep conversion work

This commit is contained in:
Folkert 2022-12-19 19:57:31 +01:00
parent 0f46ea83d0
commit bc9c813fec
No known key found for this signature in database
GPG Key ID: 1F17F6FFD112B97C
4 changed files with 183 additions and 46 deletions

View File

@ -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

View File

@ -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);

View File

@ -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(

View File

@ -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 =