forked from M-Labs/nac3
core: BoundedIxed Ixed & ArraySlice optics
This commit is contained in:
parent
867f6ccf8e
commit
259958aded
|
@ -6,7 +6,7 @@ use inkwell::{
|
||||||
};
|
};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
|
||||||
use super::CodeGenContext;
|
use super::{CodeGenContext, CodeGenerator};
|
||||||
|
|
||||||
// TODO: Write a taxonomy
|
// TODO: Write a taxonomy
|
||||||
|
|
||||||
|
@ -124,6 +124,12 @@ impl<'ctx, AddresseeOptic> OpticValue<'ctx> for Address<'ctx, AddresseeOptic> {
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct AddressLens<AddresseeOptic>(pub AddresseeOptic);
|
pub struct AddressLens<AddresseeOptic>(pub AddresseeOptic);
|
||||||
|
|
||||||
|
impl<AddresseeOptic> AddressLens<AddresseeOptic> {
|
||||||
|
pub fn new_opaque<'ctx>(&self, ctx: &CodeGenContext<'ctx, '_>) -> AddressLens<IntLens<'ctx>> {
|
||||||
|
AddressLens(IntLens(ctx.ctx.i8_type()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'ctx, AddresseeOptic: Optic<'ctx>> Optic<'ctx> for AddressLens<AddresseeOptic> {
|
impl<'ctx, AddresseeOptic: Optic<'ctx>> Optic<'ctx> for AddressLens<AddresseeOptic> {
|
||||||
type Value = Address<'ctx, AddresseeOptic>;
|
type Value = Address<'ctx, AddresseeOptic>;
|
||||||
|
|
||||||
|
@ -341,3 +347,89 @@ impl<'ctx, AddresseeOptic: StructureOptic<'ctx>> Address<'ctx, AddresseeOptic> {
|
||||||
field.get(ctx, self.address, field.name)
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue