Skip to content

Commit

Permalink
Merge pull request #165 from Wodann/fix/dereference-heap
Browse files Browse the repository at this point in the history
fix(codegen): dereferencing of gc(struct) in wrappers
  • Loading branch information
baszalmstra authored May 8, 2020
2 parents 22c5594 + bf8e4ed commit ff08f1c
Show file tree
Hide file tree
Showing 3 changed files with 202 additions and 14 deletions.
33 changes: 19 additions & 14 deletions crates/mun_codegen/src/ir/body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,15 @@ impl<'a, 'b, D: IrDatabase> BodyIrGenerator<'a, 'b, D> {
.enumerate()
.map(|(idx, ty)| {
let param = self.fn_value.get_nth_param(idx as u32).unwrap();
self.opt_deref_value(ty.clone(), param)
if let Some(s) = ty.as_struct() {
if s.data(self.db).memory_kind == abi::StructMemoryKind::Value {
deref_heap_value(&self.builder, param)
} else {
param
}
} else {
param
}
})
.collect();

Expand Down Expand Up @@ -557,25 +565,12 @@ impl<'a, 'b, D: IrDatabase> BodyIrGenerator<'a, 'b, D> {

/// Given an expression and the type of the expression, optionally dereference the value.
fn opt_deref_value(&mut self, ty: hir::Ty, value: BasicValueEnum) -> BasicValueEnum {
/// Derefs a heap-allocated value. As we introduce a layer of indirection for hot
/// reloading, we need to first load the pointer that points to the memory block.
fn deref_heap_value(builder: &Builder, value: BasicValueEnum) -> BasicValueEnum {
let mem_ptr = builder
.build_load(value.into_pointer_value(), "mem_ptr")
.into_pointer_value();

builder.build_load(mem_ptr, "deref")
}

match ty {
hir::Ty::Apply(hir::ApplicationTy {
ctor: hir::TypeCtor::Struct(s),
..
}) => match s.data(self.db).memory_kind {
hir::StructMemoryKind::GC => deref_heap_value(&self.builder, value),
hir::StructMemoryKind::Value if self.params.make_marshallable => {
deref_heap_value(&self.builder, value)
}
hir::StructMemoryKind::Value => value,
},
_ => value,
Expand Down Expand Up @@ -1284,3 +1279,13 @@ impl<'a, 'b, D: IrDatabase> BodyIrGenerator<'a, 'b, D> {
}
}
}

/// Derefs a heap-allocated value. As we introduce a layer of indirection for hot
/// reloading, we need to first load the pointer that points to the memory block.
fn deref_heap_value(builder: &Builder, value: BasicValueEnum) -> BasicValueEnum {
let mem_ptr = builder
.build_load(value.into_pointer_value(), "mem_ptr")
.into_pointer_value();

builder.build_load(mem_ptr, "deref")
}
154 changes: 154 additions & 0 deletions crates/mun_codegen/src/snapshots/test__nested_structs.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
---
source: crates/mun_codegen/src/test.rs
expression: "struct(gc) GcStruct(f32, f32);\nstruct(value) ValueStruct(f32, f32);\n\nstruct(gc) GcWrapper(GcStruct, ValueStruct)\nstruct(value) ValueWrapper(GcStruct, ValueStruct);\n\npub fn new_gc_struct(a: f32, b: f32) -> GcStruct {\n GcStruct(a, b)\n}\n\npub fn new_value_struct(a: f32, b: f32) -> ValueStruct {\n ValueStruct(a, b)\n}\n\npub fn new_gc_wrapper(a: GcStruct, b: ValueStruct) -> GcWrapper {\n GcWrapper(a, b)\n}\n\npub fn new_value_wrapper(a: GcStruct, b: ValueStruct) -> ValueWrapper {\n ValueWrapper(a, b)\n}"
---
; == FILE IR =====================================
; ModuleID = 'main.mun'
source_filename = "main.mun"

%DispatchTable = type { i8* addrspace(4)* (i8 addrspace(4)*, i8*)* }
%struct.MunTypeInfo = type { [16 x i8], i8 addrspace(4)*, i32, i8, i8 }
%GcStruct = type { float, float }
%ValueStruct = type { float, float }
%GcWrapper = type { %GcStruct* addrspace(4)*, %ValueStruct }
%ValueWrapper = type { %GcStruct* addrspace(4)*, %ValueStruct }

@allocatorHandle = external global i8*
@dispatchTable = external global %DispatchTable
@global_type_table = external global [8 x %struct.MunTypeInfo addrspace(4)*]

define %GcStruct* addrspace(4)* @new_gc_struct(float, float) {
body:
%init = insertvalue %GcStruct undef, float %0, 0
%init3 = insertvalue %GcStruct %init, float %1, 1
%new_ptr = load i8* addrspace(4)* (i8 addrspace(4)*, i8*)*, i8* addrspace(4)* (i8 addrspace(4)*, i8*)** getelementptr inbounds (%DispatchTable, %DispatchTable* @dispatchTable, i32 0, i32 0)
%GcStruct_ptr = load %struct.MunTypeInfo addrspace(4)*, %struct.MunTypeInfo addrspace(4)** getelementptr inbounds ([8 x %struct.MunTypeInfo addrspace(4)*], [8 x %struct.MunTypeInfo addrspace(4)*]* @global_type_table, i32 0, i32 5)
%type_info_ptr_to_i8_ptr = bitcast %struct.MunTypeInfo addrspace(4)* %GcStruct_ptr to i8 addrspace(4)*
%allocator_handle = load i8*, i8** @allocatorHandle
%new = call i8* addrspace(4)* %new_ptr(i8 addrspace(4)* %type_info_ptr_to_i8_ptr, i8* %allocator_handle)
%GcStruct_ptr_ptr = bitcast i8* addrspace(4)* %new to %GcStruct* addrspace(4)*
%GcStruct_mem_ptr = load %GcStruct*, %GcStruct* addrspace(4)* %GcStruct_ptr_ptr
store %GcStruct %init3, %GcStruct* %GcStruct_mem_ptr
ret %GcStruct* addrspace(4)* %GcStruct_ptr_ptr
}

define %ValueStruct @new_value_struct(float, float) {
body:
%init = insertvalue %ValueStruct undef, float %0, 0
%init3 = insertvalue %ValueStruct %init, float %1, 1
ret %ValueStruct %init3
}

define %ValueStruct* addrspace(4)* @new_value_struct_wrapper(float, float) {
body:
%new_value_struct = call %ValueStruct @new_value_struct(float %0, float %1)
%new_ptr = load i8* addrspace(4)* (i8 addrspace(4)*, i8*)*, i8* addrspace(4)* (i8 addrspace(4)*, i8*)** getelementptr inbounds (%DispatchTable, %DispatchTable* @dispatchTable, i32 0, i32 0)
%ValueStruct_ptr = load %struct.MunTypeInfo addrspace(4)*, %struct.MunTypeInfo addrspace(4)** getelementptr inbounds ([8 x %struct.MunTypeInfo addrspace(4)*], [8 x %struct.MunTypeInfo addrspace(4)*]* @global_type_table, i32 0, i32 2)
%type_info_ptr_to_i8_ptr = bitcast %struct.MunTypeInfo addrspace(4)* %ValueStruct_ptr to i8 addrspace(4)*
%allocator_handle = load i8*, i8** @allocatorHandle
%new = call i8* addrspace(4)* %new_ptr(i8 addrspace(4)* %type_info_ptr_to_i8_ptr, i8* %allocator_handle)
%ValueStruct_ptr_ptr = bitcast i8* addrspace(4)* %new to %ValueStruct* addrspace(4)*
%ValueStruct_mem_ptr = load %ValueStruct*, %ValueStruct* addrspace(4)* %ValueStruct_ptr_ptr
store %ValueStruct %new_value_struct, %ValueStruct* %ValueStruct_mem_ptr
ret %ValueStruct* addrspace(4)* %ValueStruct_ptr_ptr
}

define %GcWrapper* addrspace(4)* @new_gc_wrapper(%GcStruct* addrspace(4)*, %ValueStruct) {
body:
%.fca.0.extract = extractvalue %ValueStruct %1, 0
%.fca.1.extract = extractvalue %ValueStruct %1, 1
%init = insertvalue %GcWrapper undef, %GcStruct* addrspace(4)* %0, 0
%init3 = insertvalue %GcWrapper %init, %ValueStruct %1, 1
%new_ptr = load i8* addrspace(4)* (i8 addrspace(4)*, i8*)*, i8* addrspace(4)* (i8 addrspace(4)*, i8*)** getelementptr inbounds (%DispatchTable, %DispatchTable* @dispatchTable, i32 0, i32 0)
%GcWrapper_ptr = load %struct.MunTypeInfo addrspace(4)*, %struct.MunTypeInfo addrspace(4)** getelementptr inbounds ([8 x %struct.MunTypeInfo addrspace(4)*], [8 x %struct.MunTypeInfo addrspace(4)*]* @global_type_table, i32 0, i32 3)
%type_info_ptr_to_i8_ptr = bitcast %struct.MunTypeInfo addrspace(4)* %GcWrapper_ptr to i8 addrspace(4)*
%allocator_handle = load i8*, i8** @allocatorHandle
%new = call i8* addrspace(4)* %new_ptr(i8 addrspace(4)* %type_info_ptr_to_i8_ptr, i8* %allocator_handle)
%GcWrapper_ptr_ptr = bitcast i8* addrspace(4)* %new to %GcWrapper* addrspace(4)*
%GcWrapper_mem_ptr = load %GcWrapper*, %GcWrapper* addrspace(4)* %GcWrapper_ptr_ptr
store %GcWrapper %init3, %GcWrapper* %GcWrapper_mem_ptr
ret %GcWrapper* addrspace(4)* %GcWrapper_ptr_ptr
}

define %GcWrapper* addrspace(4)* @new_gc_wrapper_wrapper(%GcStruct* addrspace(4)*, %ValueStruct* addrspace(4)*) {
body:
%mem_ptr = load %ValueStruct*, %ValueStruct* addrspace(4)* %1
%deref = load %ValueStruct, %ValueStruct* %mem_ptr
%new_gc_wrapper = call %GcWrapper* addrspace(4)* @new_gc_wrapper(%GcStruct* addrspace(4)* %0, %ValueStruct %deref)
ret %GcWrapper* addrspace(4)* %new_gc_wrapper
}

define %ValueWrapper @new_value_wrapper(%GcStruct* addrspace(4)*, %ValueStruct) {
body:
%.fca.0.extract = extractvalue %ValueStruct %1, 0
%.fca.1.extract = extractvalue %ValueStruct %1, 1
%init = insertvalue %ValueWrapper undef, %GcStruct* addrspace(4)* %0, 0
%init3 = insertvalue %ValueWrapper %init, %ValueStruct %1, 1
ret %ValueWrapper %init3
}

define %ValueWrapper* addrspace(4)* @new_value_wrapper_wrapper(%GcStruct* addrspace(4)*, %ValueStruct* addrspace(4)*) {
body:
%mem_ptr = load %ValueStruct*, %ValueStruct* addrspace(4)* %1
%deref = load %ValueStruct, %ValueStruct* %mem_ptr
%new_value_wrapper = call %ValueWrapper @new_value_wrapper(%GcStruct* addrspace(4)* %0, %ValueStruct %deref)
%new_ptr = load i8* addrspace(4)* (i8 addrspace(4)*, i8*)*, i8* addrspace(4)* (i8 addrspace(4)*, i8*)** getelementptr inbounds (%DispatchTable, %DispatchTable* @dispatchTable, i32 0, i32 0)
%ValueWrapper_ptr = load %struct.MunTypeInfo addrspace(4)*, %struct.MunTypeInfo addrspace(4)** getelementptr inbounds ([8 x %struct.MunTypeInfo addrspace(4)*], [8 x %struct.MunTypeInfo addrspace(4)*]* @global_type_table, i32 0, i32 4)
%type_info_ptr_to_i8_ptr = bitcast %struct.MunTypeInfo addrspace(4)* %ValueWrapper_ptr to i8 addrspace(4)*
%allocator_handle = load i8*, i8** @allocatorHandle
%new = call i8* addrspace(4)* %new_ptr(i8 addrspace(4)* %type_info_ptr_to_i8_ptr, i8* %allocator_handle)
%ValueWrapper_ptr_ptr = bitcast i8* addrspace(4)* %new to %ValueWrapper* addrspace(4)*
%ValueWrapper_mem_ptr = load %ValueWrapper*, %ValueWrapper* addrspace(4)* %ValueWrapper_ptr_ptr
store %ValueWrapper %new_value_wrapper, %ValueWrapper* %ValueWrapper_mem_ptr
ret %ValueWrapper* addrspace(4)* %ValueWrapper_ptr_ptr
}


; == GROUP IR ====================================
; ModuleID = 'group_name'
source_filename = "group_name"

%DispatchTable = type { i8* addrspace(4)* (i8 addrspace(4)*, i8*)* }
%struct.MunTypeInfo = type { [16 x i8], i8 addrspace(4)*, i32, i8, i8 }
%struct.MunStructInfo = type { i8 addrspace(4)* addrspace(4)*, %struct.MunTypeInfo addrspace(4)* addrspace(4)*, i16 addrspace(4)*, i16, i8 }

@dispatchTable = global %DispatchTable zeroinitializer
@"type_info::<*const TypeInfo>::name" = private unnamed_addr constant [16 x i8] c"*const TypeInfo\00"
@"type_info::<*const TypeInfo>" = private unnamed_addr constant %struct.MunTypeInfo { [16 x i8] c"=\A1-\1F\C2\A7\88`d\90\F4\B5\BEE}x", [16 x i8]* @"type_info::<*const TypeInfo>::name", i32 64, i8 8, i8 0 }
@"type_info::<core::f32>::name" = private unnamed_addr constant [10 x i8] c"core::f32\00"
@"type_info::<core::f32>" = private unnamed_addr constant %struct.MunTypeInfo { [16 x i8] c"P\19b7\A8k\F2\81P\FB\83\F5P\B0\82!", [10 x i8]* @"type_info::<core::f32>::name", i32 32, i8 4, i8 0 }
@"type_info::<ValueStruct>::name" = private unnamed_addr constant [12 x i8] c"ValueStruct\00"
@"struct_info::<ValueStruct>::field_names" = private unnamed_addr constant [2 x i8] c"0\00"
@"struct_info::<ValueStruct>::field_names.1" = private unnamed_addr constant [2 x i8] c"1\00"
@0 = private unnamed_addr constant [2 x i8 addrspace(4)*] [i8 addrspace(4)* @"struct_info::<ValueStruct>::field_names", i8 addrspace(4)* @"struct_info::<ValueStruct>::field_names.1"]
@"struct_info::<ValueStruct>::field_types" = private unnamed_addr constant [2 x %struct.MunTypeInfo addrspace(4)*] [%struct.MunTypeInfo addrspace(4)* @"type_info::<core::f32>", %struct.MunTypeInfo addrspace(4)* @"type_info::<core::f32>"]
@"struct_info::<ValueStruct>::field_offsets" = private unnamed_addr constant [2 x i16] [i16 0, i16 4]
@"type_info::<ValueStruct>" = private unnamed_addr constant { %struct.MunTypeInfo, %struct.MunStructInfo } { %struct.MunTypeInfo { [16 x i8] c"U0{\87\5C\04Q/\95!$\A2\F1\A9\F9W", [12 x i8]* @"type_info::<ValueStruct>::name", i32 64, i8 4, i8 1 }, %struct.MunStructInfo { [2 x i8 addrspace(4)*]* @0, [2 x %struct.MunTypeInfo addrspace(4)*]* @"struct_info::<ValueStruct>::field_types", [2 x i16]* @"struct_info::<ValueStruct>::field_offsets", i16 2, i8 1 } }
@"type_info::<GcWrapper>::name" = private unnamed_addr constant [10 x i8] c"GcWrapper\00"
@"struct_info::<GcWrapper>::field_names" = private unnamed_addr constant [2 x i8] c"0\00"
@"struct_info::<GcWrapper>::field_names.2" = private unnamed_addr constant [2 x i8] c"1\00"
@1 = private unnamed_addr constant [2 x i8 addrspace(4)*] [i8 addrspace(4)* @"struct_info::<GcWrapper>::field_names", i8 addrspace(4)* @"struct_info::<GcWrapper>::field_names.2"]
@"type_info::<GcStruct>::name" = private unnamed_addr constant [9 x i8] c"GcStruct\00"
@"struct_info::<GcStruct>::field_names" = private unnamed_addr constant [2 x i8] c"0\00"
@"struct_info::<GcStruct>::field_names.3" = private unnamed_addr constant [2 x i8] c"1\00"
@2 = private unnamed_addr constant [2 x i8 addrspace(4)*] [i8 addrspace(4)* @"struct_info::<GcStruct>::field_names", i8 addrspace(4)* @"struct_info::<GcStruct>::field_names.3"]
@"struct_info::<GcStruct>::field_types" = private unnamed_addr constant [2 x %struct.MunTypeInfo addrspace(4)*] [%struct.MunTypeInfo addrspace(4)* @"type_info::<core::f32>", %struct.MunTypeInfo addrspace(4)* @"type_info::<core::f32>"]
@"struct_info::<GcStruct>::field_offsets" = private unnamed_addr constant [2 x i16] [i16 0, i16 4]
@"type_info::<GcStruct>" = private unnamed_addr constant { %struct.MunTypeInfo, %struct.MunStructInfo } { %struct.MunTypeInfo { [16 x i8] c"\B9)lg\01\95k@E\B4(\CB\CAGX\E1", [9 x i8]* @"type_info::<GcStruct>::name", i32 64, i8 4, i8 1 }, %struct.MunStructInfo { [2 x i8 addrspace(4)*]* @2, [2 x %struct.MunTypeInfo addrspace(4)*]* @"struct_info::<GcStruct>::field_types", [2 x i16]* @"struct_info::<GcStruct>::field_offsets", i16 2, i8 0 } }
@"struct_info::<GcWrapper>::field_types" = private unnamed_addr constant [2 x %struct.MunTypeInfo addrspace(4)*] [%struct.MunTypeInfo addrspace(4)* @"type_info::<GcStruct>", %struct.MunTypeInfo addrspace(4)* @"type_info::<ValueStruct>"]
@"struct_info::<GcWrapper>::field_offsets" = private unnamed_addr constant [2 x i16] [i16 0, i16 8]
@"type_info::<GcWrapper>" = private unnamed_addr constant { %struct.MunTypeInfo, %struct.MunStructInfo } { %struct.MunTypeInfo { [16 x i8] c"cR\F04\B9\E3&)\14|\B77\C4jQ\D5", [10 x i8]* @"type_info::<GcWrapper>::name", i32 128, i8 8, i8 1 }, %struct.MunStructInfo { [2 x i8 addrspace(4)*]* @1, [2 x %struct.MunTypeInfo addrspace(4)*]* @"struct_info::<GcWrapper>::field_types", [2 x i16]* @"struct_info::<GcWrapper>::field_offsets", i16 2, i8 0 } }
@"type_info::<ValueWrapper>::name" = private unnamed_addr constant [13 x i8] c"ValueWrapper\00"
@"struct_info::<ValueWrapper>::field_names" = private unnamed_addr constant [2 x i8] c"0\00"
@"struct_info::<ValueWrapper>::field_names.4" = private unnamed_addr constant [2 x i8] c"1\00"
@3 = private unnamed_addr constant [2 x i8 addrspace(4)*] [i8 addrspace(4)* @"struct_info::<ValueWrapper>::field_names", i8 addrspace(4)* @"struct_info::<ValueWrapper>::field_names.4"]
@"struct_info::<ValueWrapper>::field_types" = private unnamed_addr constant [2 x %struct.MunTypeInfo addrspace(4)*] [%struct.MunTypeInfo addrspace(4)* @"type_info::<GcStruct>", %struct.MunTypeInfo addrspace(4)* @"type_info::<ValueStruct>"]
@"struct_info::<ValueWrapper>::field_offsets" = private unnamed_addr constant [2 x i16] [i16 0, i16 8]
@"type_info::<ValueWrapper>" = private unnamed_addr constant { %struct.MunTypeInfo, %struct.MunStructInfo } { %struct.MunTypeInfo { [16 x i8] c"\99\1A\7F\CB\B36\A4\8Br\07\FB\7F\F0\86S\9F", [13 x i8]* @"type_info::<ValueWrapper>::name", i32 128, i8 8, i8 1 }, %struct.MunStructInfo { [2 x i8 addrspace(4)*]* @3, [2 x %struct.MunTypeInfo addrspace(4)*]* @"struct_info::<ValueWrapper>::field_types", [2 x i16]* @"struct_info::<ValueWrapper>::field_offsets", i16 2, i8 1 } }
@"type_info::<*const *mut core::void>::name" = private unnamed_addr constant [23 x i8] c"*const *mut core::void\00"
@"type_info::<*const *mut core::void>" = private unnamed_addr constant %struct.MunTypeInfo { [16 x i8] c"\C5fO\BD\84\DF\06\BFd+\B1\9Abv\CE\00", [23 x i8]* @"type_info::<*const *mut core::void>::name", i32 64, i8 8, i8 0 }
@"type_info::<*mut core::void>::name" = private unnamed_addr constant [16 x i8] c"*mut core::void\00"
@"type_info::<*mut core::void>" = private unnamed_addr constant %struct.MunTypeInfo { [16 x i8] c"\F0Y\22\FC\95\9E\7F\CE\08T\B1\A2\CD\A7\FAz", [16 x i8]* @"type_info::<*mut core::void>::name", i32 64, i8 8, i8 0 }
@global_type_table = global [8 x %struct.MunTypeInfo addrspace(4)*] [%struct.MunTypeInfo addrspace(4)* @"type_info::<*const TypeInfo>", %struct.MunTypeInfo addrspace(4)* @"type_info::<core::f32>", %struct.MunTypeInfo addrspace(4)* @"type_info::<ValueStruct>", %struct.MunTypeInfo addrspace(4)* @"type_info::<GcWrapper>", %struct.MunTypeInfo addrspace(4)* @"type_info::<ValueWrapper>", %struct.MunTypeInfo addrspace(4)* @"type_info::<GcStruct>", %struct.MunTypeInfo addrspace(4)* @"type_info::<*const *mut core::void>", %struct.MunTypeInfo addrspace(4)* @"type_info::<*mut core::void>"]
@allocatorHandle = unnamed_addr global i8* null

29 changes: 29 additions & 0 deletions crates/mun_codegen/src/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -776,6 +776,35 @@ fn incremental_compilation() {
// TODO: Add support for multiple files in a group
}

#[test]
fn nested_structs() {
test_snapshot(
r#"
struct(gc) GcStruct(f32, f32);
struct(value) ValueStruct(f32, f32);
struct(gc) GcWrapper(GcStruct, ValueStruct)
struct(value) ValueWrapper(GcStruct, ValueStruct);
pub fn new_gc_struct(a: f32, b: f32) -> GcStruct {
GcStruct(a, b)
}
pub fn new_value_struct(a: f32, b: f32) -> ValueStruct {
ValueStruct(a, b)
}
pub fn new_gc_wrapper(a: GcStruct, b: ValueStruct) -> GcWrapper {
GcWrapper(a, b)
}
pub fn new_value_wrapper(a: GcStruct, b: ValueStruct) -> ValueWrapper {
ValueWrapper(a, b)
}
"#,
);
}

fn test_snapshot(text: &str) {
test_snapshot_with_optimization(text, OptimizationLevel::Default);
}
Expand Down

0 comments on commit ff08f1c

Please sign in to comment.