mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-29 14:54:47 +00:00
Revert "Attempt to bitcast structs"
This reverts commit a5b50730c33437f459da8705ee186f8f354c2454.
This commit is contained in:
parent
ab79e20956
commit
ceb9cdd452
2 changed files with 69 additions and 24 deletions
|
@ -3,7 +3,7 @@ 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, IntType};
|
use inkwell::types::{BasicTypeEnum, IntType, StructType};
|
||||||
use inkwell::values::BasicValueEnum::{self, *};
|
use inkwell::values::BasicValueEnum::{self, *};
|
||||||
use inkwell::values::{FunctionValue, IntValue, PointerValue, StructValue};
|
use inkwell::values::{FunctionValue, IntValue, PointerValue, StructValue};
|
||||||
use inkwell::{FloatPredicate, IntPredicate};
|
use inkwell::{FloatPredicate, IntPredicate};
|
||||||
|
@ -449,20 +449,33 @@ pub fn build_expr<'a, 'ctx, 'env>(
|
||||||
// different types/sizes)
|
// different types/sizes)
|
||||||
//
|
//
|
||||||
// In llvm, we must be explicit about the type of value we're creating: we can't just
|
// In llvm, we must be explicit about the type of value we're creating: we can't just
|
||||||
// make a unspecified block of memory. So what we do is create a struct containing one
|
// make a unspecified block of memory. So what we do is create a byte array of the
|
||||||
// field - an integer whose size is the desired size for the entire struct.
|
// desired size. Then when we know which tag we have (which is here, in this function),
|
||||||
// Then when we know which tag we have (which is here, in this function),
|
// we need to cast that down to the array of bytes that llvm expects
|
||||||
// we cast the giant-integer struct to the more specific struct with the actual fields.
|
|
||||||
// with one field, and have that field be as big as necessary.
|
|
||||||
//
|
//
|
||||||
// This technique comes from:
|
// There is the bitcast instruction, but it doesn't work for arrays. So we need to jump
|
||||||
|
// through some hoops using store and load to get this to work: the array is put into a
|
||||||
|
// one-element struct, which can be cast to the desired type.
|
||||||
//
|
//
|
||||||
// https://stackoverflow.com/questions/19549942/extracting-a-value-from-an-union
|
// This tricks comes from
|
||||||
let whole_bits = whole_size * 8;
|
// https://github.com/raviqqe/ssf/blob/bc32aae68940d5bddf5984128e85af75ca4f4686/ssf-llvm/src/expression_compiler.rs#L116
|
||||||
let generic_struct_size = BasicTypeEnum::IntType(ctx.custom_width_int_type(whole_bits));
|
|
||||||
let generic_struct_type = ctx.struct_type(&[generic_struct_size], false);
|
|
||||||
|
|
||||||
builder.build_bitcast(struct_val, generic_struct_type, "generic_struct")
|
let array_type = ctx.i8_type().array_type(whole_size);
|
||||||
|
|
||||||
|
let result = cast_basic_basic(
|
||||||
|
builder,
|
||||||
|
struct_val.into_struct_value().into(),
|
||||||
|
array_type.into(),
|
||||||
|
);
|
||||||
|
|
||||||
|
// For unclear reasons, we can't cast an array to a struct on the other side.
|
||||||
|
// the solution is to wrap the array in a struct (yea...)
|
||||||
|
let wrapper_type = ctx.struct_type(&[array_type.into()], false);
|
||||||
|
let mut wrapper_val = wrapper_type.const_zero().into();
|
||||||
|
wrapper_val = builder
|
||||||
|
.build_insert_value(wrapper_val, result, 0, "insert_field")
|
||||||
|
.unwrap();
|
||||||
|
wrapper_val.into_struct_value().into()
|
||||||
}
|
}
|
||||||
AccessAtIndex {
|
AccessAtIndex {
|
||||||
index,
|
index,
|
||||||
|
@ -512,9 +525,7 @@ pub fn build_expr<'a, 'ctx, 'env>(
|
||||||
// cast the argument bytes into the desired shape for this tag
|
// cast the argument bytes into the desired shape for this tag
|
||||||
let argument = build_expr(env, &scope, parent, expr, procs).into_struct_value();
|
let argument = build_expr(env, &scope, parent, expr, procs).into_struct_value();
|
||||||
|
|
||||||
let struct_value = builder
|
let struct_value = cast_struct_struct(builder, argument, struct_type);
|
||||||
.build_bitcast(argument, struct_type, "generic_struct")
|
|
||||||
.into_struct_value();
|
|
||||||
|
|
||||||
builder
|
builder
|
||||||
.build_extract_value(struct_value, *index as u32, "")
|
.build_extract_value(struct_value, *index as u32, "")
|
||||||
|
@ -539,6 +550,38 @@ fn load_symbol<'a, 'ctx, 'env>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Cast a struct to another struct of the same (or smaller?) size
|
||||||
|
fn cast_struct_struct<'ctx>(
|
||||||
|
builder: &Builder<'ctx>,
|
||||||
|
from_value: StructValue<'ctx>,
|
||||||
|
to_type: StructType<'ctx>,
|
||||||
|
) -> StructValue<'ctx> {
|
||||||
|
cast_basic_basic(builder, from_value.into(), to_type.into()).into_struct_value()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Cast a value to another value of the same (or smaller?) size
|
||||||
|
fn cast_basic_basic<'ctx>(
|
||||||
|
builder: &Builder<'ctx>,
|
||||||
|
from_value: BasicValueEnum<'ctx>,
|
||||||
|
to_type: BasicTypeEnum<'ctx>,
|
||||||
|
) -> BasicValueEnum<'ctx> {
|
||||||
|
use inkwell::types::BasicType;
|
||||||
|
// store the value in memory
|
||||||
|
let argument_pointer = builder.build_alloca(from_value.get_type(), "");
|
||||||
|
builder.build_store(argument_pointer, from_value);
|
||||||
|
|
||||||
|
// then read it back as a different type
|
||||||
|
let to_type_pointer = builder
|
||||||
|
.build_bitcast(
|
||||||
|
argument_pointer,
|
||||||
|
to_type.ptr_type(inkwell::AddressSpace::Generic),
|
||||||
|
"",
|
||||||
|
)
|
||||||
|
.into_pointer_value();
|
||||||
|
|
||||||
|
builder.build_load(to_type_pointer, "")
|
||||||
|
}
|
||||||
|
|
||||||
fn extract_tag_discriminant<'a, 'ctx, 'env>(
|
fn extract_tag_discriminant<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
from_value: StructValue<'ctx>,
|
from_value: StructValue<'ctx>,
|
||||||
|
@ -547,10 +590,7 @@ fn extract_tag_discriminant<'a, 'ctx, 'env>(
|
||||||
.context
|
.context
|
||||||
.struct_type(&[env.context.i64_type().into()], false);
|
.struct_type(&[env.context.i64_type().into()], false);
|
||||||
|
|
||||||
let struct_value = env
|
let struct_value = cast_struct_struct(env.builder, from_value, struct_type);
|
||||||
.builder
|
|
||||||
.build_bitcast(from_value, struct_type, "generic_struct")
|
|
||||||
.into_struct_value();
|
|
||||||
|
|
||||||
env.builder
|
env.builder
|
||||||
.build_extract_value(struct_value, 0, "")
|
.build_extract_value(struct_value, 0, "")
|
||||||
|
|
|
@ -94,11 +94,16 @@ pub fn basic_type_from_layout<'ctx>(
|
||||||
.as_basic_type_enum()
|
.as_basic_type_enum()
|
||||||
}
|
}
|
||||||
Union(_) => {
|
Union(_) => {
|
||||||
let union_size = layout.stack_size(ptr_bytes);
|
// TODO make this dynamic
|
||||||
let union_bits = union_size * 8;
|
let ptr_size = std::mem::size_of::<i64>();
|
||||||
let generic_struct_size =
|
let union_size = layout.stack_size(ptr_size as u32);
|
||||||
BasicTypeEnum::IntType(context.custom_width_int_type(union_bits));
|
|
||||||
context.struct_type(&[generic_struct_size], false).into()
|
let array_type = context
|
||||||
|
.i8_type()
|
||||||
|
.array_type(union_size)
|
||||||
|
.as_basic_type_enum();
|
||||||
|
|
||||||
|
context.struct_type(&[array_type], false).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
Builtin(builtin) => match builtin {
|
Builtin(builtin) => match builtin {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue