forked from M-Labs/nac3
core: split codegen optics into modules
This commit is contained in:
parent
9a82b033b6
commit
e4998ccec8
|
@ -1,9 +1,7 @@
|
||||||
use inkwell::types::IntType;
|
use inkwell::types::IntType;
|
||||||
|
|
||||||
use crate::codegen::{
|
use crate::codegen::optics::*;
|
||||||
optics::{Address, AddressLens, ArraySlice, FieldBuilder, GepGetter, IntLens, StructureOptic},
|
use crate::codegen::CodeGenContext;
|
||||||
CodeGenContext,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct StrLens<'ctx> {
|
pub struct StrLens<'ctx> {
|
||||||
|
@ -51,10 +49,7 @@ impl<'ctx> StructureOptic<'ctx> for NpArrayLens<'ctx> {
|
||||||
"NDArray"
|
"NDArray"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_fields(
|
fn build_fields(&self, builder: &mut FieldBuilder<'ctx>) -> Self::Fields {
|
||||||
&self,
|
|
||||||
builder: &mut crate::codegen::optics::FieldBuilder<'ctx>,
|
|
||||||
) -> Self::Fields {
|
|
||||||
NpArrayFields {
|
NpArrayFields {
|
||||||
data: builder.add_field("data", AddressLens(IntLens(builder.ctx.i8_type()))),
|
data: builder.add_field("data", AddressLens(IntLens(builder.ctx.i8_type()))),
|
||||||
itemsize: builder.add_field("itemsize", IntLens(builder.ctx.i8_type())),
|
itemsize: builder.add_field("itemsize", IntLens(builder.ctx.i8_type())),
|
||||||
|
@ -96,10 +91,7 @@ impl<'ctx> StructureOptic<'ctx> for IrrtStringLens {
|
||||||
"String"
|
"String"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_fields(
|
fn build_fields(&self, builder: &mut FieldBuilder<'ctx>) -> Self::Fields {
|
||||||
&self,
|
|
||||||
builder: &mut crate::codegen::optics::FieldBuilder<'ctx>,
|
|
||||||
) -> Self::Fields {
|
|
||||||
let llvm_i8 = builder.ctx.i8_type();
|
let llvm_i8 = builder.ctx.i8_type();
|
||||||
let llvm_i32 = builder.ctx.i32_type();
|
let llvm_i32 = builder.ctx.i32_type();
|
||||||
IrrtStringFields {
|
IrrtStringFields {
|
||||||
|
@ -157,10 +149,7 @@ impl<'ctx> StructureOptic<'ctx> for ErrorContextLens {
|
||||||
"ErrorContext"
|
"ErrorContext"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_fields(
|
fn build_fields(&self, builder: &mut FieldBuilder<'ctx>) -> Self::Fields {
|
||||||
&self,
|
|
||||||
builder: &mut crate::codegen::optics::FieldBuilder<'ctx>,
|
|
||||||
) -> Self::Fields {
|
|
||||||
ErrorContextFields {
|
ErrorContextFields {
|
||||||
error_ids: builder.add_field("error_ids", AddressLens(ErrorIdsLens)),
|
error_ids: builder.add_field("error_ids", AddressLens(ErrorIdsLens)),
|
||||||
error_id: builder.add_field("error_id", IntLens(builder.ctx.i32_type())),
|
error_id: builder.add_field("error_id", IntLens(builder.ctx.i32_type())),
|
||||||
|
|
|
@ -4,7 +4,11 @@ use inkwell::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::codegen::{
|
use crate::codegen::{
|
||||||
optics::{Address, AddressLens, IntLens, Optic, OpticValue, Prism},
|
optics::{
|
||||||
|
address::{Address, AddressLens},
|
||||||
|
core::{Optic, OpticValue, Prism},
|
||||||
|
int::IntLens,
|
||||||
|
},
|
||||||
CodeGenContext, CodeGenerator,
|
CodeGenContext, CodeGenerator,
|
||||||
};
|
};
|
||||||
use crate::util::SizeVariant;
|
use crate::util::SizeVariant;
|
||||||
|
|
|
@ -5,10 +5,10 @@ use inkwell::{
|
||||||
values::{BasicValueEnum, IntValue},
|
values::{BasicValueEnum, IntValue},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use crate::codegen::optics::*;
|
||||||
use crate::{
|
use crate::{
|
||||||
codegen::{
|
codegen::{
|
||||||
classes::{ListValue, UntypedArrayLikeAccessor},
|
classes::{ListValue, UntypedArrayLikeAccessor},
|
||||||
optics::{opaque_address_lens, Address, AddressLens, ArraySlice, IntLens, Ixed, Optic},
|
|
||||||
stmt::gen_for_callback_incrementing,
|
stmt::gen_for_callback_incrementing,
|
||||||
CodeGenContext, CodeGenerator,
|
CodeGenContext, CodeGenerator,
|
||||||
},
|
},
|
||||||
|
|
|
@ -26,7 +26,7 @@ use inkwell::{
|
||||||
use irrt::classes::StrLens;
|
use irrt::classes::StrLens;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use nac3parser::ast::{Location, Stmt, StrRef};
|
use nac3parser::ast::{Location, Stmt, StrRef};
|
||||||
use optics::Optic;
|
use optics::Optic as _;
|
||||||
use parking_lot::{Condvar, Mutex};
|
use parking_lot::{Condvar, Mutex};
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::sync::{
|
use std::sync::{
|
||||||
|
|
|
@ -1,449 +0,0 @@
|
||||||
use inkwell::{
|
|
||||||
context::Context,
|
|
||||||
types::{BasicType, BasicTypeEnum, IntType},
|
|
||||||
values::{AnyValue, BasicValue, BasicValueEnum, IntValue, PointerValue, StructValue},
|
|
||||||
AddressSpace,
|
|
||||||
};
|
|
||||||
use itertools::Itertools;
|
|
||||||
|
|
||||||
use super::{CodeGenContext, CodeGenerator};
|
|
||||||
|
|
||||||
// TODO: Write a taxonomy
|
|
||||||
|
|
||||||
pub trait OpticValue<'ctx> {
|
|
||||||
fn get_llvm_value(&self) -> BasicValueEnum<'ctx>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'ctx, T: BasicValue<'ctx>> OpticValue<'ctx> for T {
|
|
||||||
fn get_llvm_value(&self) -> BasicValueEnum<'ctx> {
|
|
||||||
self.as_basic_value_enum()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: The interface is unintuitive
|
|
||||||
pub trait Optic<'ctx>: Clone {
|
|
||||||
type Value: OpticValue<'ctx>;
|
|
||||||
|
|
||||||
fn get_llvm_type(&self, ctx: &'ctx Context) -> BasicTypeEnum<'ctx>;
|
|
||||||
|
|
||||||
fn alloca(&self, ctx: &CodeGenContext<'ctx, '_>, name: &str) -> Address<'ctx, Self> {
|
|
||||||
let ptr = ctx.builder.build_alloca(self.get_llvm_type(ctx.ctx), name).unwrap();
|
|
||||||
Address { addressee_optic: self.clone(), address: ptr }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait Prism<'ctx>: Optic<'ctx> {
|
|
||||||
// TODO: Return error if `review` fails
|
|
||||||
fn review<V: AnyValue<'ctx>>(&self, value: V) -> Self::Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait MemoryGetter<'ctx>: Optic<'ctx> {
|
|
||||||
fn get(
|
|
||||||
&self,
|
|
||||||
ctx: &CodeGenContext<'ctx, '_>,
|
|
||||||
pointer: PointerValue<'ctx>,
|
|
||||||
name: &str,
|
|
||||||
) -> Self::Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait MemorySetter<'ctx>: Optic<'ctx> {
|
|
||||||
fn set(&self, ctx: &CodeGenContext<'ctx, '_>, pointer: PointerValue<'ctx>, value: &Self::Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE: I wanted to make Int8Lens, Int16Lens, Int32Lens, with all
|
|
||||||
// having the trait IsIntLens, and implement `impl <S: IsIntLens> Optic<S> for T`,
|
|
||||||
// but that clashes with StructureOptic!!
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub struct IntLens<'ctx>(pub IntType<'ctx>);
|
|
||||||
|
|
||||||
impl<'ctx> IntLens<'ctx> {
|
|
||||||
#[must_use]
|
|
||||||
pub fn int8(ctx: &'ctx Context) -> IntLens<'ctx> {
|
|
||||||
IntLens(ctx.i8_type())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[must_use]
|
|
||||||
pub fn int32(ctx: &'ctx Context) -> IntLens<'ctx> {
|
|
||||||
IntLens(ctx.i32_type())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[must_use]
|
|
||||||
pub fn int64(ctx: &'ctx Context) -> IntLens<'ctx> {
|
|
||||||
IntLens(ctx.i64_type())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'ctx> Optic<'ctx> for IntLens<'ctx> {
|
|
||||||
type Value = IntValue<'ctx>;
|
|
||||||
|
|
||||||
fn get_llvm_type(&self, _ctx: &'ctx Context) -> BasicTypeEnum<'ctx> {
|
|
||||||
self.0.as_basic_type_enum()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'ctx> Prism<'ctx> for IntLens<'ctx> {
|
|
||||||
fn review<V: AnyValue<'ctx>>(&self, value: V) -> Self::Value {
|
|
||||||
let int = value.as_any_value_enum().into_int_value();
|
|
||||||
debug_assert_eq!(int.get_type().get_bit_width(), self.0.get_bit_width());
|
|
||||||
int
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'ctx> MemoryGetter<'ctx> for IntLens<'ctx> {
|
|
||||||
fn get(
|
|
||||||
&self,
|
|
||||||
ctx: &CodeGenContext<'ctx, '_>,
|
|
||||||
pointer: PointerValue<'ctx>,
|
|
||||||
name: &str,
|
|
||||||
) -> Self::Value {
|
|
||||||
self.review(ctx.builder.build_load(pointer, name).unwrap())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'ctx> MemorySetter<'ctx> for IntLens<'ctx> {
|
|
||||||
fn set(&self, ctx: &CodeGenContext<'ctx, '_>, pointer: PointerValue<'ctx>, int: &Self::Value) {
|
|
||||||
debug_assert_eq!(int.get_type().get_bit_width(), self.0.get_bit_width());
|
|
||||||
ctx.builder.build_store(pointer, int.as_basic_value_enum()).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct Address<'ctx, AddresseeOptic> {
|
|
||||||
pub addressee_optic: AddresseeOptic,
|
|
||||||
pub address: PointerValue<'ctx>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'ctx, AddresseeOptic> Address<'ctx, AddresseeOptic> {
|
|
||||||
pub fn cast_to<S: Optic<'ctx>>(
|
|
||||||
&self,
|
|
||||||
ctx: &CodeGenContext<'ctx, '_>,
|
|
||||||
new_optic: S,
|
|
||||||
) -> Address<'ctx, S> {
|
|
||||||
let to_ptr_type = new_optic.get_llvm_type(ctx.ctx).ptr_type(AddressSpace::default());
|
|
||||||
let casted_address =
|
|
||||||
ctx.builder.build_pointer_cast(self.address, to_ptr_type, "ptr_casted").unwrap();
|
|
||||||
Address { addressee_optic: new_optic, address: casted_address }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn cast_to_opaque(&self, ctx: &CodeGenContext<'ctx, '_>) -> Address<'ctx, IntLens<'ctx>> {
|
|
||||||
self.cast_to(ctx, IntLens::int8(ctx.ctx))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'ctx, AddresseeOptic> OpticValue<'ctx> for Address<'ctx, AddresseeOptic> {
|
|
||||||
fn get_llvm_value(&self) -> BasicValueEnum<'ctx> {
|
|
||||||
self.address.as_basic_value_enum()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct AddressLens<AddresseeOptic>(pub AddresseeOptic);
|
|
||||||
|
|
||||||
#[must_use]
|
|
||||||
pub fn opaque_address_lens(ctx: &Context) -> AddressLens<IntLens<'_>> {
|
|
||||||
AddressLens(IntLens::int8(ctx))
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'ctx, AddresseeOptic: Optic<'ctx>> Optic<'ctx> for AddressLens<AddresseeOptic> {
|
|
||||||
type Value = Address<'ctx, AddresseeOptic>;
|
|
||||||
|
|
||||||
fn get_llvm_type(&self, ctx: &'ctx Context) -> BasicTypeEnum<'ctx> {
|
|
||||||
self.0.get_llvm_type(ctx).ptr_type(AddressSpace::default()).as_basic_type_enum()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'ctx, AddresseeOptic: Optic<'ctx>> Prism<'ctx> for AddressLens<AddresseeOptic> {
|
|
||||||
fn review<V: AnyValue<'ctx>>(&self, value: V) -> Self::Value {
|
|
||||||
Address {
|
|
||||||
addressee_optic: self.0.clone(),
|
|
||||||
address: value.as_any_value_enum().into_pointer_value(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'ctx, AddressesOptic: Optic<'ctx>> MemoryGetter<'ctx> for AddressLens<AddressesOptic> {
|
|
||||||
fn get(
|
|
||||||
&self,
|
|
||||||
ctx: &CodeGenContext<'ctx, '_>,
|
|
||||||
pointer: PointerValue<'ctx>,
|
|
||||||
name: &str,
|
|
||||||
) -> Self::Value {
|
|
||||||
self.review(ctx.builder.build_load(pointer, name).unwrap())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'ctx, AddressesOptic: Optic<'ctx>> MemorySetter<'ctx> for AddressLens<AddressesOptic> {
|
|
||||||
fn set(
|
|
||||||
&self,
|
|
||||||
ctx: &CodeGenContext<'ctx, '_>,
|
|
||||||
pointer: PointerValue<'ctx>,
|
|
||||||
value: &Self::Value,
|
|
||||||
) {
|
|
||||||
ctx.builder.build_store(pointer, value.address).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// To make [`Address`] convenient to use
|
|
||||||
impl<'ctx, AddresseeOptic: MemoryGetter<'ctx>> Address<'ctx, AddresseeOptic> {
|
|
||||||
pub fn load(&self, ctx: &CodeGenContext<'ctx, '_>, name: &str) -> AddresseeOptic::Value {
|
|
||||||
self.addressee_optic.get(ctx, self.address, name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// To make [`Address`] convenient to use
|
|
||||||
impl<'ctx, AddresseeOptic: MemorySetter<'ctx>> Address<'ctx, AddresseeOptic> {
|
|
||||||
pub fn store(&self, ctx: &CodeGenContext<'ctx, '_>, value: &AddresseeOptic::Value) {
|
|
||||||
self.addressee_optic.set(ctx, self.address, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ((Memory, Pointer) -> ElementOptic::Value*)
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct GepGetter<ElementOptic> {
|
|
||||||
/// The LLVM GEP index
|
|
||||||
pub gep_index: u64,
|
|
||||||
/// Element (or field in the context of `struct`s) name. Used for cosmetics.
|
|
||||||
pub name: &'static str,
|
|
||||||
/// The lens to view the actual value after applying this [`FieldLens<T>`]
|
|
||||||
pub element_optic: ElementOptic,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'ctx, ElementOptic: Optic<'ctx>> Optic<'ctx> for GepGetter<ElementOptic> {
|
|
||||||
type Value = Address<'ctx, ElementOptic>;
|
|
||||||
|
|
||||||
fn get_llvm_type(&self, ctx: &'ctx Context) -> BasicTypeEnum<'ctx> {
|
|
||||||
self.element_optic.get_llvm_type(ctx).ptr_type(AddressSpace::default()).as_basic_type_enum()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'ctx, ElementOptic: Optic<'ctx>> MemoryGetter<'ctx> for GepGetter<ElementOptic> {
|
|
||||||
fn get(
|
|
||||||
&self,
|
|
||||||
ctx: &CodeGenContext<'ctx, '_>,
|
|
||||||
pointer: PointerValue<'ctx>,
|
|
||||||
name: &str,
|
|
||||||
) -> Self::Value {
|
|
||||||
let llvm_i32 = ctx.ctx.i32_type(); // TODO: I think I'm not supposed to *just* use i32 for GEP like that
|
|
||||||
let element_ptr = unsafe {
|
|
||||||
ctx.builder
|
|
||||||
.build_in_bounds_gep(
|
|
||||||
pointer,
|
|
||||||
&[llvm_i32.const_zero(), llvm_i32.const_int(self.gep_index, false)],
|
|
||||||
name,
|
|
||||||
)
|
|
||||||
.unwrap()
|
|
||||||
};
|
|
||||||
Address { address: element_ptr, addressee_optic: self.element_optic.clone() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only used by [`FieldBuilder`]
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct FieldInfo<'ctx> {
|
|
||||||
gep_index: u64,
|
|
||||||
name: &'ctx str,
|
|
||||||
llvm_type: BasicTypeEnum<'ctx>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct FieldBuilder<'ctx> {
|
|
||||||
pub ctx: &'ctx Context,
|
|
||||||
gep_index_counter: u64,
|
|
||||||
struct_name: &'ctx str,
|
|
||||||
fields: Vec<FieldInfo<'ctx>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'ctx> FieldBuilder<'ctx> {
|
|
||||||
#[must_use]
|
|
||||||
pub fn new(ctx: &'ctx Context, struct_name: &'ctx str) -> Self {
|
|
||||||
FieldBuilder { ctx, gep_index_counter: 0, struct_name, fields: Vec::new() }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn next_gep_index(&mut self) -> u64 {
|
|
||||||
let index = self.gep_index_counter;
|
|
||||||
self.gep_index_counter += 1;
|
|
||||||
index
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_field<ElementOptic: Optic<'ctx>>(
|
|
||||||
&mut self,
|
|
||||||
name: &'static str,
|
|
||||||
element_optic: ElementOptic,
|
|
||||||
) -> GepGetter<ElementOptic> {
|
|
||||||
let gep_index = self.next_gep_index();
|
|
||||||
|
|
||||||
self.fields.push(FieldInfo {
|
|
||||||
gep_index,
|
|
||||||
name,
|
|
||||||
llvm_type: element_optic.get_llvm_type(self.ctx),
|
|
||||||
});
|
|
||||||
|
|
||||||
GepGetter { gep_index, name, element_optic }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait StructureOptic<'ctx>: Clone {
|
|
||||||
// Fields of optics
|
|
||||||
type Fields;
|
|
||||||
|
|
||||||
// TODO: Make it an associated function instead?
|
|
||||||
fn struct_name(&self) -> &'static str;
|
|
||||||
|
|
||||||
fn build_fields(&self, builder: &mut FieldBuilder<'ctx>) -> Self::Fields;
|
|
||||||
|
|
||||||
fn get_fields(&self, ctx: &'ctx Context) -> Self::Fields {
|
|
||||||
let mut builder = FieldBuilder::new(ctx, self.struct_name());
|
|
||||||
self.build_fields(&mut builder)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct OpticalStructValue<'ctx, StructOptic> {
|
|
||||||
optic: StructOptic,
|
|
||||||
llvm: StructValue<'ctx>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'ctx, StructOptic> OpticValue<'ctx> for OpticalStructValue<'ctx, StructOptic> {
|
|
||||||
fn get_llvm_value(&self) -> BasicValueEnum<'ctx> {
|
|
||||||
self.llvm.as_basic_value_enum()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: check StructType
|
|
||||||
impl<'ctx, T: StructureOptic<'ctx>> Optic<'ctx> for T {
|
|
||||||
type Value = OpticalStructValue<'ctx, Self>;
|
|
||||||
|
|
||||||
fn get_llvm_type(&self, ctx: &'ctx Context) -> BasicTypeEnum<'ctx> {
|
|
||||||
let mut builder = FieldBuilder::new(ctx, self.struct_name());
|
|
||||||
self.build_fields(&mut builder); // Self::Fields is discarded
|
|
||||||
|
|
||||||
let field_types =
|
|
||||||
builder.fields.iter().map(|field_info| field_info.llvm_type).collect_vec();
|
|
||||||
ctx.struct_type(&field_types, false).as_basic_type_enum()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'ctx, T: StructureOptic<'ctx>> MemoryGetter<'ctx> for T {
|
|
||||||
fn get(
|
|
||||||
&self,
|
|
||||||
ctx: &CodeGenContext<'ctx, '_>,
|
|
||||||
pointer: PointerValue<'ctx>,
|
|
||||||
name: &str,
|
|
||||||
) -> Self::Value {
|
|
||||||
OpticalStructValue {
|
|
||||||
optic: self.clone(),
|
|
||||||
llvm: ctx.builder.build_load(pointer, name).unwrap().into_struct_value(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'ctx, T: StructureOptic<'ctx>> MemorySetter<'ctx> for T {
|
|
||||||
fn set(
|
|
||||||
&self,
|
|
||||||
ctx: &CodeGenContext<'ctx, '_>,
|
|
||||||
pointer: PointerValue<'ctx>,
|
|
||||||
value: &Self::Value,
|
|
||||||
) {
|
|
||||||
ctx.builder.build_store(pointer, value.llvm).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'ctx, AddresseeOptic: StructureOptic<'ctx>> Address<'ctx, AddresseeOptic> {
|
|
||||||
pub fn focus<GetFieldGepFn, FieldElementOptic: Optic<'ctx>>(
|
|
||||||
&self,
|
|
||||||
ctx: &CodeGenContext<'ctx, '_>,
|
|
||||||
get_field_gep_fn: GetFieldGepFn,
|
|
||||||
) -> Address<'ctx, FieldElementOptic>
|
|
||||||
where
|
|
||||||
GetFieldGepFn: FnOnce(&AddresseeOptic::Fields) -> &GepGetter<FieldElementOptic>,
|
|
||||||
{
|
|
||||||
let fields = self.addressee_optic.get_fields(ctx.ctx);
|
|
||||||
let field = get_field_gep_fn(&fields);
|
|
||||||
field.get(ctx, self.address, field.name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Name inspired by https://hackage.haskell.org/package/lens-5.3.2/docs/Control-Lens-At.html#t:Ixed
|
|
||||||
pub trait Ixed<'ctx, ElementOptic> {
|
|
||||||
// TODO: Interface/Method to expose the IntType of index?
|
|
||||||
// or even make index itself parameterized? (probably no)
|
|
||||||
|
|
||||||
fn ix(
|
|
||||||
&self,
|
|
||||||
ctx: &CodeGenContext<'ctx, '_>,
|
|
||||||
index: IntValue<'ctx>,
|
|
||||||
name: &str,
|
|
||||||
) -> Address<'ctx, ElementOptic>;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Can do interface seggregation
|
|
||||||
pub trait BoundedIxed<'ctx, ElementOptic>: Ixed<'ctx, ElementOptic> {
|
|
||||||
fn num_elements(&self, ctx: &CodeGenContext<'ctx, '_>) -> IntValue<'ctx>;
|
|
||||||
|
|
||||||
// Check if 0 <= index < self.num_elements()
|
|
||||||
fn ix_bounds_checked<G: CodeGenerator + ?Sized>(
|
|
||||||
&self,
|
|
||||||
generator: &mut G,
|
|
||||||
ctx: &mut CodeGenContext<'ctx, '_>,
|
|
||||||
index: IntValue<'ctx>,
|
|
||||||
name: &str,
|
|
||||||
) -> Address<'ctx, ElementOptic> {
|
|
||||||
let num_elements = self.num_elements(ctx);
|
|
||||||
let int_type = num_elements.get_type(); // NOTE: Weird get_type(), see comment under `trait Ixed`
|
|
||||||
|
|
||||||
assert_eq!(int_type.get_bit_width(), index.get_type().get_bit_width()); // Might as well check bit width to catch bugs
|
|
||||||
|
|
||||||
// TODO: SGE or UGE? or make it defined by the implementee?
|
|
||||||
|
|
||||||
// Check `0 <= index`
|
|
||||||
let lower_bounded = ctx
|
|
||||||
.builder
|
|
||||||
.build_int_compare(
|
|
||||||
inkwell::IntPredicate::SLE,
|
|
||||||
int_type.const_zero(),
|
|
||||||
index,
|
|
||||||
"lower_bounded",
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// Check `index < num_elements`
|
|
||||||
let upper_bounded = ctx
|
|
||||||
.builder
|
|
||||||
.build_int_compare(inkwell::IntPredicate::SLT, index, num_elements, "upper_bounded")
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// Compute `0 <= index && index < num_elements`
|
|
||||||
let bounded = ctx.builder.build_and(lower_bounded, upper_bounded, "bounded").unwrap();
|
|
||||||
|
|
||||||
// Assert `bounded`
|
|
||||||
ctx.make_assert(generator, bounded, "0:IndexError", "nac3core LLVM codegen attempting to access out of bounds array index {0}. Must satisfy 0 <= index < {2}", [Some(index), Some(num_elements), None], ctx.current_loc);
|
|
||||||
|
|
||||||
// ...and finally do indexing
|
|
||||||
self.ix(ctx, index, name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ArraySlice<'ctx, ElementOptic> {
|
|
||||||
pub num_elements: IntValue<'ctx>,
|
|
||||||
pub base: Address<'ctx, ElementOptic>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'ctx, ElementOptic: Optic<'ctx>> Ixed<'ctx, ElementOptic> for ArraySlice<'ctx, ElementOptic> {
|
|
||||||
fn ix(
|
|
||||||
&self,
|
|
||||||
ctx: &CodeGenContext<'ctx, '_>,
|
|
||||||
index: IntValue<'ctx>,
|
|
||||||
name: &str,
|
|
||||||
) -> Address<'ctx, ElementOptic> {
|
|
||||||
let element_addr =
|
|
||||||
unsafe { ctx.builder.build_in_bounds_gep(self.base.address, &[index], name).unwrap() };
|
|
||||||
Address { address: element_addr, addressee_optic: self.base.addressee_optic.clone() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'ctx, ElementOptic: Optic<'ctx>> BoundedIxed<'ctx, ElementOptic>
|
|
||||||
for ArraySlice<'ctx, ElementOptic>
|
|
||||||
{
|
|
||||||
fn num_elements(&self, _ctx: &CodeGenContext<'ctx, '_>) -> IntValue<'ctx> {
|
|
||||||
self.num_elements
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,103 @@
|
||||||
|
use inkwell::{
|
||||||
|
context::Context,
|
||||||
|
types::{BasicType, BasicTypeEnum},
|
||||||
|
values::{AnyValue, BasicValue, BasicValueEnum, PointerValue},
|
||||||
|
AddressSpace,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::codegen::CodeGenContext;
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
core::{MemoryGetter, MemorySetter, Optic, OpticValue, Prism},
|
||||||
|
int::IntLens,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Address<'ctx, AddresseeOptic> {
|
||||||
|
pub addressee_optic: AddresseeOptic,
|
||||||
|
pub address: PointerValue<'ctx>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ctx, AddresseeOptic> Address<'ctx, AddresseeOptic> {
|
||||||
|
pub fn cast_to<S: Optic<'ctx>>(
|
||||||
|
&self,
|
||||||
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
|
new_optic: S,
|
||||||
|
) -> Address<'ctx, S> {
|
||||||
|
let to_ptr_type = new_optic.get_llvm_type(ctx.ctx).ptr_type(AddressSpace::default());
|
||||||
|
let casted_address =
|
||||||
|
ctx.builder.build_pointer_cast(self.address, to_ptr_type, "ptr_casted").unwrap();
|
||||||
|
Address { addressee_optic: new_optic, address: casted_address }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cast_to_opaque(&self, ctx: &CodeGenContext<'ctx, '_>) -> Address<'ctx, IntLens<'ctx>> {
|
||||||
|
self.cast_to(ctx, IntLens::int8(ctx.ctx))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ctx, AddresseeOptic> OpticValue<'ctx> for Address<'ctx, AddresseeOptic> {
|
||||||
|
fn get_llvm_value(&self) -> BasicValueEnum<'ctx> {
|
||||||
|
self.address.as_basic_value_enum()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct AddressLens<AddresseeOptic>(pub AddresseeOptic);
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn opaque_address_lens(ctx: &Context) -> AddressLens<IntLens<'_>> {
|
||||||
|
AddressLens(IntLens::int8(ctx))
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ctx, AddresseeOptic: Optic<'ctx>> Optic<'ctx> for AddressLens<AddresseeOptic> {
|
||||||
|
type Value = Address<'ctx, AddresseeOptic>;
|
||||||
|
|
||||||
|
fn get_llvm_type(&self, ctx: &'ctx Context) -> BasicTypeEnum<'ctx> {
|
||||||
|
self.0.get_llvm_type(ctx).ptr_type(AddressSpace::default()).as_basic_type_enum()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ctx, AddresseeOptic: Optic<'ctx>> Prism<'ctx> for AddressLens<AddresseeOptic> {
|
||||||
|
fn review<V: AnyValue<'ctx>>(&self, value: V) -> Self::Value {
|
||||||
|
Address {
|
||||||
|
addressee_optic: self.0.clone(),
|
||||||
|
address: value.as_any_value_enum().into_pointer_value(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ctx, AddressesOptic: Optic<'ctx>> MemoryGetter<'ctx> for AddressLens<AddressesOptic> {
|
||||||
|
fn get(
|
||||||
|
&self,
|
||||||
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
|
pointer: PointerValue<'ctx>,
|
||||||
|
name: &str,
|
||||||
|
) -> Self::Value {
|
||||||
|
self.review(ctx.builder.build_load(pointer, name).unwrap())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ctx, AddressesOptic: Optic<'ctx>> MemorySetter<'ctx> for AddressLens<AddressesOptic> {
|
||||||
|
fn set(
|
||||||
|
&self,
|
||||||
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
|
pointer: PointerValue<'ctx>,
|
||||||
|
value: &Self::Value,
|
||||||
|
) {
|
||||||
|
ctx.builder.build_store(pointer, value.address).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// To make [`Address`] convenient to use
|
||||||
|
impl<'ctx, AddresseeOptic: MemoryGetter<'ctx>> Address<'ctx, AddresseeOptic> {
|
||||||
|
pub fn load(&self, ctx: &CodeGenContext<'ctx, '_>, name: &str) -> AddresseeOptic::Value {
|
||||||
|
self.addressee_optic.get(ctx, self.address, name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// To make [`Address`] convenient to use
|
||||||
|
impl<'ctx, AddresseeOptic: MemorySetter<'ctx>> Address<'ctx, AddresseeOptic> {
|
||||||
|
pub fn store(&self, ctx: &CodeGenContext<'ctx, '_>, value: &AddresseeOptic::Value) {
|
||||||
|
self.addressee_optic.set(ctx, self.address, value);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
use inkwell::{
|
||||||
|
context::Context,
|
||||||
|
types::BasicTypeEnum,
|
||||||
|
values::{AnyValue, BasicValue, BasicValueEnum, PointerValue},
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::codegen::CodeGenContext;
|
||||||
|
|
||||||
|
use super::address::Address;
|
||||||
|
|
||||||
|
// TODO: Write a taxonomy
|
||||||
|
|
||||||
|
pub trait OpticValue<'ctx> {
|
||||||
|
fn get_llvm_value(&self) -> BasicValueEnum<'ctx>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ctx, T: BasicValue<'ctx>> OpticValue<'ctx> for T {
|
||||||
|
fn get_llvm_value(&self) -> BasicValueEnum<'ctx> {
|
||||||
|
self.as_basic_value_enum()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: The interface is unintuitive
|
||||||
|
pub trait Optic<'ctx>: Clone {
|
||||||
|
type Value: OpticValue<'ctx>;
|
||||||
|
|
||||||
|
fn get_llvm_type(&self, ctx: &'ctx Context) -> BasicTypeEnum<'ctx>;
|
||||||
|
|
||||||
|
fn alloca(&self, ctx: &CodeGenContext<'ctx, '_>, name: &str) -> Address<'ctx, Self> {
|
||||||
|
let ptr = ctx.builder.build_alloca(self.get_llvm_type(ctx.ctx), name).unwrap();
|
||||||
|
Address { addressee_optic: self.clone(), address: ptr }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Prism<'ctx>: Optic<'ctx> {
|
||||||
|
// TODO: Return error if `review` fails
|
||||||
|
fn review<V: AnyValue<'ctx>>(&self, value: V) -> Self::Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait MemoryGetter<'ctx>: Optic<'ctx> {
|
||||||
|
fn get(
|
||||||
|
&self,
|
||||||
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
|
pointer: PointerValue<'ctx>,
|
||||||
|
name: &str,
|
||||||
|
) -> Self::Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait MemorySetter<'ctx>: Optic<'ctx> {
|
||||||
|
fn set(&self, ctx: &CodeGenContext<'ctx, '_>, pointer: PointerValue<'ctx>, value: &Self::Value);
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
use inkwell::{
|
||||||
|
context::Context,
|
||||||
|
types::{BasicType, BasicTypeEnum},
|
||||||
|
values::PointerValue,
|
||||||
|
AddressSpace,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::codegen::CodeGenContext;
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
address::Address,
|
||||||
|
core::{MemoryGetter, Optic},
|
||||||
|
};
|
||||||
|
|
||||||
|
// ((Memory, Pointer) -> ElementOptic::Value*)
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct GepGetter<ElementOptic> {
|
||||||
|
/// The LLVM GEP index
|
||||||
|
pub gep_index: u64,
|
||||||
|
/// Element (or field in the context of `struct`s) name. Used for cosmetics.
|
||||||
|
pub name: &'static str,
|
||||||
|
/// The lens to view the actual value after applying this [`FieldLens<T>`]
|
||||||
|
pub element_optic: ElementOptic,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ctx, ElementOptic: Optic<'ctx>> Optic<'ctx> for GepGetter<ElementOptic> {
|
||||||
|
type Value = Address<'ctx, ElementOptic>;
|
||||||
|
|
||||||
|
fn get_llvm_type(&self, ctx: &'ctx Context) -> BasicTypeEnum<'ctx> {
|
||||||
|
self.element_optic.get_llvm_type(ctx).ptr_type(AddressSpace::default()).as_basic_type_enum()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ctx, ElementOptic: Optic<'ctx>> MemoryGetter<'ctx> for GepGetter<ElementOptic> {
|
||||||
|
fn get(
|
||||||
|
&self,
|
||||||
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
|
pointer: PointerValue<'ctx>,
|
||||||
|
name: &str,
|
||||||
|
) -> Self::Value {
|
||||||
|
let llvm_i32 = ctx.ctx.i32_type(); // TODO: I think I'm not supposed to *just* use i32 for GEP like that
|
||||||
|
let element_ptr = unsafe {
|
||||||
|
ctx.builder
|
||||||
|
.build_in_bounds_gep(
|
||||||
|
pointer,
|
||||||
|
&[llvm_i32.const_zero(), llvm_i32.const_int(self.gep_index, false)],
|
||||||
|
name,
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
};
|
||||||
|
Address { address: element_ptr, addressee_optic: self.element_optic.clone() }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
use inkwell::{
|
||||||
|
context::Context,
|
||||||
|
types::{BasicType, BasicTypeEnum, IntType},
|
||||||
|
values::{AnyValue, BasicValue, IntValue, PointerValue},
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::codegen::CodeGenContext;
|
||||||
|
|
||||||
|
use super::core::{MemoryGetter, MemorySetter, Optic, Prism};
|
||||||
|
|
||||||
|
// NOTE: I wanted to make Int8Lens, Int16Lens, Int32Lens, with all
|
||||||
|
// having the trait IsIntLens, and implement `impl <S: IsIntLens> Optic<S> for T`,
|
||||||
|
// but that clashes with StructureOptic!!
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct IntLens<'ctx>(pub IntType<'ctx>);
|
||||||
|
|
||||||
|
impl<'ctx> IntLens<'ctx> {
|
||||||
|
#[must_use]
|
||||||
|
pub fn int8(ctx: &'ctx Context) -> IntLens<'ctx> {
|
||||||
|
IntLens(ctx.i8_type())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn int32(ctx: &'ctx Context) -> IntLens<'ctx> {
|
||||||
|
IntLens(ctx.i32_type())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn int64(ctx: &'ctx Context) -> IntLens<'ctx> {
|
||||||
|
IntLens(ctx.i64_type())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ctx> Optic<'ctx> for IntLens<'ctx> {
|
||||||
|
type Value = IntValue<'ctx>;
|
||||||
|
|
||||||
|
fn get_llvm_type(&self, _ctx: &'ctx Context) -> BasicTypeEnum<'ctx> {
|
||||||
|
self.0.as_basic_type_enum()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ctx> Prism<'ctx> for IntLens<'ctx> {
|
||||||
|
fn review<V: AnyValue<'ctx>>(&self, value: V) -> Self::Value {
|
||||||
|
let int = value.as_any_value_enum().into_int_value();
|
||||||
|
debug_assert_eq!(int.get_type().get_bit_width(), self.0.get_bit_width());
|
||||||
|
int
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ctx> MemoryGetter<'ctx> for IntLens<'ctx> {
|
||||||
|
fn get(
|
||||||
|
&self,
|
||||||
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
|
pointer: PointerValue<'ctx>,
|
||||||
|
name: &str,
|
||||||
|
) -> Self::Value {
|
||||||
|
self.review(ctx.builder.build_load(pointer, name).unwrap())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ctx> MemorySetter<'ctx> for IntLens<'ctx> {
|
||||||
|
fn set(&self, ctx: &CodeGenContext<'ctx, '_>, pointer: PointerValue<'ctx>, int: &Self::Value) {
|
||||||
|
debug_assert_eq!(int.get_type().get_bit_width(), self.0.get_bit_width());
|
||||||
|
ctx.builder.build_store(pointer, int.as_basic_value_enum()).unwrap();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
use inkwell::values::IntValue;
|
||||||
|
|
||||||
|
use crate::codegen::{CodeGenContext, CodeGenerator};
|
||||||
|
|
||||||
|
use super::address::Address;
|
||||||
|
|
||||||
|
// Name inspired by https://hackage.haskell.org/package/lens-5.3.2/docs/Control-Lens-At.html#t:Ixed
|
||||||
|
pub trait Ixed<'ctx, ElementOptic> {
|
||||||
|
// TODO: Interface/Method to expose the IntType of index?
|
||||||
|
// or even make index itself parameterized? (probably no)
|
||||||
|
|
||||||
|
fn ix(
|
||||||
|
&self,
|
||||||
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
|
index: IntValue<'ctx>,
|
||||||
|
name: &str,
|
||||||
|
) -> Address<'ctx, ElementOptic>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Can do interface seggregation
|
||||||
|
pub trait BoundedIxed<'ctx, ElementOptic>: Ixed<'ctx, ElementOptic> {
|
||||||
|
fn num_elements(&self, ctx: &CodeGenContext<'ctx, '_>) -> IntValue<'ctx>;
|
||||||
|
|
||||||
|
// Check if 0 <= index < self.num_elements()
|
||||||
|
fn ix_bounds_checked<G: CodeGenerator + ?Sized>(
|
||||||
|
&self,
|
||||||
|
generator: &mut G,
|
||||||
|
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||||
|
index: IntValue<'ctx>,
|
||||||
|
name: &str,
|
||||||
|
) -> Address<'ctx, ElementOptic> {
|
||||||
|
let num_elements = self.num_elements(ctx);
|
||||||
|
let int_type = num_elements.get_type(); // NOTE: Weird get_type(), see comment under `trait Ixed`
|
||||||
|
|
||||||
|
assert_eq!(int_type.get_bit_width(), index.get_type().get_bit_width()); // Might as well check bit width to catch bugs
|
||||||
|
|
||||||
|
// TODO: SGE or UGE? or make it defined by the implementee?
|
||||||
|
|
||||||
|
// Check `0 <= index`
|
||||||
|
let lower_bounded = ctx
|
||||||
|
.builder
|
||||||
|
.build_int_compare(
|
||||||
|
inkwell::IntPredicate::SLE,
|
||||||
|
int_type.const_zero(),
|
||||||
|
index,
|
||||||
|
"lower_bounded",
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// Check `index < num_elements`
|
||||||
|
let upper_bounded = ctx
|
||||||
|
.builder
|
||||||
|
.build_int_compare(inkwell::IntPredicate::SLT, index, num_elements, "upper_bounded")
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// Compute `0 <= index && index < num_elements`
|
||||||
|
let bounded = ctx.builder.build_and(lower_bounded, upper_bounded, "bounded").unwrap();
|
||||||
|
|
||||||
|
// Assert `bounded`
|
||||||
|
ctx.make_assert(generator, bounded, "0:IndexError", "nac3core LLVM codegen attempting to access out of bounds array index {0}. Must satisfy 0 <= index < {2}", [Some(index), Some(num_elements), None], ctx.current_loc);
|
||||||
|
|
||||||
|
// ...and finally do indexing
|
||||||
|
self.ix(ctx, index, name)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
pub mod address;
|
||||||
|
pub mod core;
|
||||||
|
pub mod gep;
|
||||||
|
pub mod int;
|
||||||
|
pub mod ixed;
|
||||||
|
pub mod slice;
|
||||||
|
pub mod structure;
|
||||||
|
|
||||||
|
pub use address::*;
|
||||||
|
pub use core::*;
|
||||||
|
pub use gep::*;
|
||||||
|
pub use int::*;
|
||||||
|
pub use ixed::*;
|
||||||
|
pub use slice::*;
|
||||||
|
pub use structure::*;
|
|
@ -0,0 +1,36 @@
|
||||||
|
use super::{
|
||||||
|
core::Optic,
|
||||||
|
ixed::{BoundedIxed, Ixed},
|
||||||
|
};
|
||||||
|
|
||||||
|
use inkwell::values::IntValue;
|
||||||
|
|
||||||
|
use crate::codegen::CodeGenContext;
|
||||||
|
|
||||||
|
use super::address::Address;
|
||||||
|
|
||||||
|
pub struct ArraySlice<'ctx, ElementOptic> {
|
||||||
|
pub num_elements: IntValue<'ctx>,
|
||||||
|
pub base: Address<'ctx, ElementOptic>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ctx, ElementOptic: Optic<'ctx>> Ixed<'ctx, ElementOptic> for ArraySlice<'ctx, ElementOptic> {
|
||||||
|
fn ix(
|
||||||
|
&self,
|
||||||
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
|
index: IntValue<'ctx>,
|
||||||
|
name: &str,
|
||||||
|
) -> Address<'ctx, ElementOptic> {
|
||||||
|
let element_addr =
|
||||||
|
unsafe { ctx.builder.build_in_bounds_gep(self.base.address, &[index], name).unwrap() };
|
||||||
|
Address { address: element_addr, addressee_optic: self.base.addressee_optic.clone() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ctx, ElementOptic: Optic<'ctx>> BoundedIxed<'ctx, ElementOptic>
|
||||||
|
for ArraySlice<'ctx, ElementOptic>
|
||||||
|
{
|
||||||
|
fn num_elements(&self, _ctx: &CodeGenContext<'ctx, '_>) -> IntValue<'ctx> {
|
||||||
|
self.num_elements
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,139 @@
|
||||||
|
use inkwell::{
|
||||||
|
context::Context,
|
||||||
|
types::{BasicType, BasicTypeEnum},
|
||||||
|
values::{BasicValue, BasicValueEnum, PointerValue, StructValue},
|
||||||
|
};
|
||||||
|
use itertools::Itertools;
|
||||||
|
|
||||||
|
use crate::codegen::CodeGenContext;
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
address::Address,
|
||||||
|
core::{MemoryGetter, MemorySetter, Optic, OpticValue},
|
||||||
|
gep::GepGetter,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub trait StructureOptic<'ctx>: Clone {
|
||||||
|
// Fields of optics
|
||||||
|
type Fields;
|
||||||
|
|
||||||
|
// TODO: Make it an associated function instead?
|
||||||
|
fn struct_name(&self) -> &'static str;
|
||||||
|
|
||||||
|
fn build_fields(&self, builder: &mut FieldBuilder<'ctx>) -> Self::Fields;
|
||||||
|
|
||||||
|
fn get_fields(&self, ctx: &'ctx Context) -> Self::Fields {
|
||||||
|
let mut builder = FieldBuilder::new(ctx, self.struct_name());
|
||||||
|
self.build_fields(&mut builder)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct OpticalStructValue<'ctx, StructOptic> {
|
||||||
|
optic: StructOptic,
|
||||||
|
llvm: StructValue<'ctx>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ctx, StructOptic> OpticValue<'ctx> for OpticalStructValue<'ctx, StructOptic> {
|
||||||
|
fn get_llvm_value(&self) -> BasicValueEnum<'ctx> {
|
||||||
|
self.llvm.as_basic_value_enum()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: check StructType
|
||||||
|
impl<'ctx, T: StructureOptic<'ctx>> Optic<'ctx> for T {
|
||||||
|
type Value = OpticalStructValue<'ctx, Self>;
|
||||||
|
|
||||||
|
fn get_llvm_type(&self, ctx: &'ctx Context) -> BasicTypeEnum<'ctx> {
|
||||||
|
let mut builder = FieldBuilder::new(ctx, self.struct_name());
|
||||||
|
self.build_fields(&mut builder); // Self::Fields is discarded
|
||||||
|
|
||||||
|
let field_types =
|
||||||
|
builder.fields.iter().map(|field_info| field_info.llvm_type).collect_vec();
|
||||||
|
ctx.struct_type(&field_types, false).as_basic_type_enum()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ctx, T: StructureOptic<'ctx>> MemoryGetter<'ctx> for T {
|
||||||
|
fn get(
|
||||||
|
&self,
|
||||||
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
|
pointer: PointerValue<'ctx>,
|
||||||
|
name: &str,
|
||||||
|
) -> Self::Value {
|
||||||
|
OpticalStructValue {
|
||||||
|
optic: self.clone(),
|
||||||
|
llvm: ctx.builder.build_load(pointer, name).unwrap().into_struct_value(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ctx, T: StructureOptic<'ctx>> MemorySetter<'ctx> for T {
|
||||||
|
fn set(
|
||||||
|
&self,
|
||||||
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
|
pointer: PointerValue<'ctx>,
|
||||||
|
value: &Self::Value,
|
||||||
|
) {
|
||||||
|
ctx.builder.build_store(pointer, value.llvm).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ctx, AddresseeOptic: StructureOptic<'ctx>> Address<'ctx, AddresseeOptic> {
|
||||||
|
pub fn focus<GetFieldGepFn, FieldElementOptic: Optic<'ctx>>(
|
||||||
|
&self,
|
||||||
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
|
get_field_gep_fn: GetFieldGepFn,
|
||||||
|
) -> Address<'ctx, FieldElementOptic>
|
||||||
|
where
|
||||||
|
GetFieldGepFn: FnOnce(&AddresseeOptic::Fields) -> &GepGetter<FieldElementOptic>,
|
||||||
|
{
|
||||||
|
let fields = self.addressee_optic.get_fields(ctx.ctx);
|
||||||
|
let field = get_field_gep_fn(&fields);
|
||||||
|
field.get(ctx, self.address, field.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only used by [`FieldBuilder`]
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct FieldInfo<'ctx> {
|
||||||
|
gep_index: u64,
|
||||||
|
name: &'ctx str,
|
||||||
|
llvm_type: BasicTypeEnum<'ctx>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct FieldBuilder<'ctx> {
|
||||||
|
pub ctx: &'ctx Context,
|
||||||
|
gep_index_counter: u64,
|
||||||
|
struct_name: &'ctx str,
|
||||||
|
fields: Vec<FieldInfo<'ctx>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ctx> FieldBuilder<'ctx> {
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(ctx: &'ctx Context, struct_name: &'ctx str) -> Self {
|
||||||
|
FieldBuilder { ctx, gep_index_counter: 0, struct_name, fields: Vec::new() }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn next_gep_index(&mut self) -> u64 {
|
||||||
|
let index = self.gep_index_counter;
|
||||||
|
self.gep_index_counter += 1;
|
||||||
|
index
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_field<ElementOptic: Optic<'ctx>>(
|
||||||
|
&mut self,
|
||||||
|
name: &'static str,
|
||||||
|
element_optic: ElementOptic,
|
||||||
|
) -> GepGetter<ElementOptic> {
|
||||||
|
let gep_index = self.next_gep_index();
|
||||||
|
|
||||||
|
self.fields.push(FieldInfo {
|
||||||
|
gep_index,
|
||||||
|
name,
|
||||||
|
llvm_type: element_optic.get_llvm_type(self.ctx),
|
||||||
|
});
|
||||||
|
|
||||||
|
GepGetter { gep_index, name, element_optic }
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue