mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-29 23:04:49 +00:00
Switch on tags in llvm
This commit is contained in:
parent
0593a39e0f
commit
f30655a103
1 changed files with 81 additions and 30 deletions
|
@ -3,9 +3,9 @@ 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;
|
use inkwell::types::{BasicTypeEnum, StructType};
|
||||||
use inkwell::values::BasicValueEnum::{self, *};
|
use inkwell::values::BasicValueEnum::{self, *};
|
||||||
use inkwell::values::{FunctionValue, IntValue, PointerValue};
|
use inkwell::values::{FunctionValue, IntValue, PointerValue, StructValue};
|
||||||
use inkwell::{AddressSpace, FloatPredicate, IntPredicate};
|
use inkwell::{AddressSpace, FloatPredicate, IntPredicate};
|
||||||
|
|
||||||
use crate::llvm::convert::{
|
use crate::llvm::convert::{
|
||||||
|
@ -440,20 +440,26 @@ pub fn build_expr<'a, 'ctx, 'env>(
|
||||||
// https://github.com/raviqqe/ssf/blob/bc32aae68940d5bddf5984128e85af75ca4f4686/ssf-llvm/src/expression_compiler.rs#L116
|
// https://github.com/raviqqe/ssf/blob/bc32aae68940d5bddf5984128e85af75ca4f4686/ssf-llvm/src/expression_compiler.rs#L116
|
||||||
|
|
||||||
let array_type = ctx.i8_type().array_type(whole_size);
|
let array_type = ctx.i8_type().array_type(whole_size);
|
||||||
let struct_pointer = builder.build_alloca(array_type, "struct_poitner");
|
|
||||||
|
|
||||||
builder.build_store(
|
let result = cast_basic_basic(
|
||||||
builder
|
builder,
|
||||||
.build_bitcast(
|
struct_val.into_struct_value().into(),
|
||||||
struct_pointer,
|
array_type.into(),
|
||||||
struct_type.ptr_type(inkwell::AddressSpace::Generic),
|
|
||||||
"",
|
|
||||||
)
|
|
||||||
.into_pointer_value(),
|
|
||||||
struct_val,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
let result = builder.build_load(struct_pointer, "");
|
// let struct_pointer = builder.build_alloca(array_type, "struct_poitner");
|
||||||
|
// builder.build_store(
|
||||||
|
// builder
|
||||||
|
// .build_bitcast(
|
||||||
|
// struct_pointer,
|
||||||
|
// struct_type.ptr_type(inkwell::AddressSpace::Generic),
|
||||||
|
// "",
|
||||||
|
// )
|
||||||
|
// .into_pointer_value(),
|
||||||
|
// struct_val,
|
||||||
|
// );
|
||||||
|
//
|
||||||
|
// let result = builder.build_load(struct_pointer, "");
|
||||||
|
|
||||||
// For unclear reasons, we can't cast an array to a struct on the other side.
|
// 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...)
|
// the solution is to wrap the array in a struct (yea...)
|
||||||
|
@ -542,24 +548,11 @@ 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 argument_pointer = builder.build_alloca(argument.get_type(), "");
|
|
||||||
builder.build_store(argument_pointer, argument);
|
|
||||||
|
|
||||||
let argument = builder
|
let struct_value = cast_struct_struct(builder, argument, struct_type);
|
||||||
.build_load(
|
|
||||||
builder
|
|
||||||
.build_bitcast(
|
|
||||||
argument_pointer,
|
|
||||||
struct_type.ptr_type(inkwell::AddressSpace::Generic),
|
|
||||||
"",
|
|
||||||
)
|
|
||||||
.into_pointer_value(),
|
|
||||||
"",
|
|
||||||
)
|
|
||||||
.into_struct_value();
|
|
||||||
|
|
||||||
builder
|
builder
|
||||||
.build_extract_value(argument, *index as u32, "")
|
.build_extract_value(struct_value, *index as u32, "")
|
||||||
.expect("desired field did not decode")
|
.expect("desired field did not decode")
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
@ -568,6 +561,54 @@ pub fn build_expr<'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>(
|
||||||
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
from_value: StructValue<'ctx>,
|
||||||
|
) -> IntValue<'ctx> {
|
||||||
|
let struct_type = env
|
||||||
|
.context
|
||||||
|
.struct_type(&[env.context.i64_type().into()], false);
|
||||||
|
|
||||||
|
let struct_value = cast_struct_struct(env.builder, from_value, struct_type);
|
||||||
|
|
||||||
|
env.builder
|
||||||
|
.build_extract_value(struct_value, 0, "")
|
||||||
|
.expect("desired field did not decode")
|
||||||
|
.into_int_value()
|
||||||
|
}
|
||||||
|
|
||||||
struct Branch2<'a> {
|
struct Branch2<'a> {
|
||||||
cond: &'a Expr<'a>,
|
cond: &'a Expr<'a>,
|
||||||
pass: &'a Expr<'a>,
|
pass: &'a Expr<'a>,
|
||||||
|
@ -619,7 +660,7 @@ fn build_switch<'a, 'ctx, 'env>(
|
||||||
let SwitchArgs {
|
let SwitchArgs {
|
||||||
branches,
|
branches,
|
||||||
cond_expr,
|
cond_expr,
|
||||||
cond_layout,
|
mut cond_layout,
|
||||||
default_branch,
|
default_branch,
|
||||||
ret_type,
|
ret_type,
|
||||||
..
|
..
|
||||||
|
@ -628,7 +669,17 @@ fn build_switch<'a, 'ctx, 'env>(
|
||||||
let cont_block = context.append_basic_block(parent, "cont");
|
let cont_block = context.append_basic_block(parent, "cont");
|
||||||
|
|
||||||
// Build the condition
|
// Build the condition
|
||||||
let cond = build_expr(env, scope, parent, cond_expr, procs).into_int_value();
|
let cond = match cond_layout {
|
||||||
|
Layout::Builtin(_) => build_expr(env, scope, parent, cond_expr, procs).into_int_value(),
|
||||||
|
Layout::Union(_) => {
|
||||||
|
// we match on the discriminant, not the whole Tag
|
||||||
|
cond_layout = Layout::Builtin(Builtin::Int64);
|
||||||
|
let full_cond = build_expr(env, scope, parent, cond_expr, procs).into_struct_value();
|
||||||
|
|
||||||
|
extract_tag_discriminant(env, full_cond)
|
||||||
|
}
|
||||||
|
other => todo!("Build switch value from layout: {:?}", other),
|
||||||
|
};
|
||||||
|
|
||||||
// Build the cases
|
// Build the cases
|
||||||
let mut incoming = Vec::with_capacity_in(branches.len(), arena);
|
let mut incoming = Vec::with_capacity_in(branches.len(), arena);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue