1
0
forked from M-Labs/nac3
This commit is contained in:
lyken 2024-07-14 17:05:45 +08:00
parent 7742fbf9e0
commit 059b130aff
10 changed files with 182 additions and 63 deletions

View File

@ -2,7 +2,7 @@ use std::marker::PhantomData;
use inkwell::{
types::{BasicType, BasicTypeEnum, IntType},
values::{BasicValueEnum, IntValue},
values::{BasicValueEnum, IntValue, PointerValue},
};
use crate::codegen::optics::*;
@ -95,7 +95,7 @@ struct Producer<'ctx, G: CodeGenerator + ?Sized, ElementOptic> {
///
/// See also [`typecheck::type_inferencer::fold_numpy_function_call_shape_argument`] to
/// learn how `shape` gets from being a Python user expression to here.
fn parse_input_shape_arg<'ctx, G>(
pub fn parse_input_shape_arg<'ctx, G>(
generator: &mut G,
ctx: &mut CodeGenContext<'ctx, '_>,
shape: BasicValueEnum<'ctx>,
@ -258,14 +258,14 @@ where
Ok(ndarray_ptr)
}
enum NDArrayInitMode<'ctx, G: CodeGenerator + ?Sized> {
NDim { ndim: IntValue<'ctx>, _phantom: PhantomData<&'ctx G> },
pub enum NDArrayInitMode<'ctx, G: CodeGenerator + ?Sized> {
NDim { ndim: IntValue<'ctx> },
Shape { shape: Producer<'ctx, G, IntLens<'ctx>> },
ShapeAndAllocaData { shape: Producer<'ctx, G, IntLens<'ctx>> },
}
/// TODO: DOCUMENT ME
fn alloca_ndarray_and_init<'ctx, G>(
pub fn alloca_ndarray_and_init<'ctx, G>(
generator: &mut G,
ctx: &mut CodeGenContext<'ctx, '_>,
elem_type: BasicTypeEnum<'ctx>,
@ -277,7 +277,7 @@ where
{
// It is implemented verbosely in order to make the initialization modes super clear in their intent.
match init_mode {
NDArrayInitMode::NDim { ndim: ndims, _phantom } => {
NDArrayInitMode::NDim { ndim } => {
let ndarray = alloca_ndarray(generator, ctx, elem_type, ndims, name)?;
Ok(ndarray)
}
@ -397,11 +397,11 @@ fn call_nac3_ndarray_nbytes<'ctx, G: CodeGenerator + ?Sized>(
.returning("nbytes", &IntLens(size_type))
}
fn call_nac3_ndarray_fill_generic<'ctx, G: CodeGenerator + ?Sized>(
pub fn call_nac3_ndarray_fill_generic<'ctx, G: CodeGenerator + ?Sized>(
generator: &mut G,
ctx: &mut CodeGenContext<'ctx, '_>,
ndarray_ptr: &Address<'ctx, NpArrayLens<'ctx>>,
fill_value_ptr: &Address<'ctx, IntLens<'ctx>>,
fill_value_ptr: PointerValue<'ctx>,
) {
let size_type = generator.get_size_type(ctx.ctx);
@ -410,6 +410,6 @@ fn call_nac3_ndarray_fill_generic<'ctx, G: CodeGenerator + ?Sized>(
&get_sized_dependent_function_name(size_type, "__nac3_ndarray_fill_generic"),
)
.arg("ndarray", &AddressLens(NpArrayLens { size_type }), ndarray_ptr)
.arg("pvalue", &opaque_address_lens(ctx.ctx), fill_value_ptr)
.arg("pvalue", &OpaqueAddressLens, fill_value_ptr)
.returning_void();
}

View File

@ -43,13 +43,13 @@ impl<'ctx, 'a> FunctionBuilder<'ctx, 'a> {
// The name is for self-documentation
#[must_use]
pub fn arg<S: Optic<'ctx>>(mut self, _name: &'static str, optic: &S, arg: &S::Value) -> Self {
pub fn arg<S: MemoryOptic<'ctx>>(mut self, _name: &'static str, optic: &S, arg: &S::MemoryValue) -> Self {
self.arguments
.push((optic.get_llvm_type(self.ctx.ctx).into(), arg.get_llvm_value().into()));
self
}
pub fn returning<S: Prism<'ctx>>(self, name: &'static str, return_prism: &S) -> S::Value {
pub fn returning<S: Prism<'ctx>>(self, name: &'static str, return_prism: &S) -> S::MemoryValue {
let (param_tys, param_vals): (Vec<_>, Vec<_>) = self.arguments.into_iter().unzip();
let function = self.ctx.module.get_function(self.fn_name).unwrap_or_else(|| {

View File

@ -26,7 +26,7 @@ use inkwell::{
use irrt::error_context::StrLens;
use itertools::Itertools;
use nac3parser::ast::{Location, Stmt, StrRef};
use optics::Optic as _;
use optics::MemoryOptic as _;
use parking_lot::{Condvar, Mutex};
use std::collections::{HashMap, HashSet};
use std::sync::{
@ -44,6 +44,7 @@ mod generator;
pub mod irrt;
pub mod llvm_intrinsics;
pub mod numpy;
pub mod numpy_new;
pub mod optics;
pub mod stmt;

View File

@ -0,0 +1,91 @@
use inkwell::values::{BasicValueEnum, PointerValue};
use nac3parser::ast::StrRef;
use crate::{
codegen::optics::build_opaque_alloca, symbol_resolver::ValueEnum, toplevel::DefinitionId, typecheck::typedef::{FunSignature, Type}
};
use super::{
irrt::{
self,
numpy::{alloca_ndarray_and_init, parse_input_shape_arg, NDArrayInitMode, NpArrayLens},
},
optics::Address,
CodeGenContext, CodeGenerator,
};
/// LLVM-typed implementation for generating the implementation for constructing an empty `NDArray`.
fn call_ndarray_empty_impl<'ctx, G>(
generator: &mut G,
ctx: &mut CodeGenContext<'ctx, '_>,
elem_ty: Type,
shape: BasicValueEnum<'ctx>,
shape_ty: Type,
name: &str,
) -> Result<Address<'ctx, NpArrayLens<'ctx>>, String>
where
G: CodeGenerator + ?Sized,
{
let elem_type = ctx.get_llvm_type(generator, elem_ty);
let shape = parse_input_shape_arg(generator, ctx, shape, shape_ty);
let ndarray_ptr = alloca_ndarray_and_init(
generator,
ctx,
elem_type,
NDArrayInitMode::ShapeAndAllocaData { shape },
name,
)?;
Ok(ndarray_ptr)
}
fn call_ndarray_fill_impl<'ctx, G>(
generator: &mut G,
ctx: &mut CodeGenContext<'ctx, '_>,
elem_ty: Type,
shape: BasicValueEnum<'ctx>,
shape_ty: Type,
fill_value: BasicValueEnum<'ctx>,
name: &str,
) -> Result<Address<'ctx, NpArrayLens<'ctx>>, String>
where
G: CodeGenerator + ?Sized,
{
let ndarray_ptr = call_ndarray_empty_impl(generator, ctx, elem_ty, shape, shape_ty, name)?;
// NOTE: fill_value's type is not checked!!
let fill_value_ptr = build_opaque_alloca(ctx, fill_value.get_type(), name);
fill_value_ptr.store(ctx, );
// let fill_value_ptr = ctx.builder.build_alloca(, "fill_value_ptr").unwrap();
// ctx.builder.build_store(fill_value_ptr, fill_value);
// let ok = irrt::numpy::call_nac3_ndarray_fill_generic(generator, ctx, ndarray_ptr, Address { fill_value_ptr } );
todo!()
Ok(ndarray_ptr)
}
/// Generates LLVM IR for `np.empty`.
pub fn gen_ndarray_empty<'ctx, G>(
context: &mut CodeGenContext<'ctx, '_>,
obj: &Option<(Type, ValueEnum<'ctx>)>,
fun: (&FunSignature, DefinitionId),
args: &[(Option<StrRef>, ValueEnum<'ctx>)],
generator: &mut dyn CodeGenerator,
) -> Result<PointerValue<'ctx>, String> {
assert!(obj.is_none());
assert_eq!(args.len(), 1);
// Parse arguments
let shape_ty = fun.0.args[0].ty;
let shape = args[0].1.clone().to_basic_value_enum(context, generator, shape_ty)?;
// Implementation
let ndarray_ptr = call_ndarray_empty_impl(
generator,
context,
context.primitives.float,
shape,
shape_ty,
"empty_ndarray",
)?;
Ok(ndarray_ptr.address)
}

View File

@ -7,10 +7,7 @@ use inkwell::{
use crate::codegen::CodeGenContext;
use super::{
core::{MemoryGetter, MemorySetter, Optic, OpticValue, Prism},
int::IntLens,
};
use super::core::{MemoryGetter, MemoryOptic, MemorySetter, OpticValue, Prism};
#[derive(Debug, Clone)]
pub struct Address<'ctx, AddresseeOptic> {
@ -19,7 +16,7 @@ pub struct Address<'ctx, AddresseeOptic> {
}
impl<'ctx, AddresseeOptic> Address<'ctx, AddresseeOptic> {
pub fn cast_to<S: Optic<'ctx>>(
pub fn cast_to<S: MemoryOptic<'ctx>>(
&self,
ctx: &CodeGenContext<'ctx, '_>,
new_optic: S,
@ -30,8 +27,8 @@ impl<'ctx, AddresseeOptic> Address<'ctx, AddresseeOptic> {
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))
pub fn cast_to_opaque(&self) -> OpaqueAddress<'ctx> {
OpaqueAddress(self.address)
}
}
@ -44,21 +41,16 @@ impl<'ctx, AddresseeOptic> OpticValue<'ctx> for Address<'ctx, AddresseeOptic> {
#[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>;
impl<'ctx, AddresseeOptic: MemoryOptic<'ctx>> MemoryOptic<'ctx> for AddressLens<AddresseeOptic> {
type MemoryValue = 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 {
impl<'ctx, AddresseeOptic: MemoryOptic<'ctx>> Prism<'ctx> for AddressLens<AddresseeOptic> {
fn review<V: AnyValue<'ctx>>(&self, value: V) -> Self::MemoryValue {
Address {
addressee_optic: self.0.clone(),
address: value.as_any_value_enum().into_pointer_value(),
@ -66,23 +58,23 @@ impl<'ctx, AddresseeOptic: Optic<'ctx>> Prism<'ctx> for AddressLens<AddresseeOpt
}
}
impl<'ctx, AddressesOptic: Optic<'ctx>> MemoryGetter<'ctx> for AddressLens<AddressesOptic> {
impl<'ctx, AddressesOptic: MemoryOptic<'ctx>> MemoryGetter<'ctx> for AddressLens<AddressesOptic> {
fn get(
&self,
ctx: &CodeGenContext<'ctx, '_>,
pointer: PointerValue<'ctx>,
name: &str,
) -> Self::Value {
) -> Self::MemoryValue {
self.review(ctx.builder.build_load(pointer, name).unwrap())
}
}
impl<'ctx, AddressesOptic: Optic<'ctx>> MemorySetter<'ctx> for AddressLens<AddressesOptic> {
impl<'ctx, AddressesOptic: MemoryOptic<'ctx>> MemorySetter<'ctx> for AddressLens<AddressesOptic> {
fn set(
&self,
ctx: &CodeGenContext<'ctx, '_>,
pointer: PointerValue<'ctx>,
value: &Self::Value,
value: &Self::MemoryValue,
) {
ctx.builder.build_store(pointer, value.address).unwrap();
}
@ -90,14 +82,49 @@ impl<'ctx, AddressesOptic: Optic<'ctx>> MemorySetter<'ctx> for AddressLens<Addre
// 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 {
pub fn load(&self, ctx: &CodeGenContext<'ctx, '_>, name: &str) -> AddresseeOptic::MemoryValue {
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) {
pub fn store(&self, ctx: &CodeGenContext<'ctx, '_>, value: &AddresseeOptic::MemoryValue) {
self.addressee_optic.set(ctx, self.address, value);
}
}
#[derive(Debug, Clone, Copy)]
pub struct OpaqueAddress<'ctx>(pub PointerValue<'ctx>);
impl<'ctx> OpaqueAddress<'ctx> {
pub fn cast_to<AddresseeOptic: MemoryOptic<'ctx>>(
&self,
ctx: &'ctx CodeGenContext,
addressee_optic: AddresseeOptic,
name: &str,
) -> Address<'ctx, AddresseeOptic> {
let ptr = ctx.builder.build_pointer_cast(
self.0,
addressee_optic.get_llvm_type(ctx.ctx).ptr_type(AddressSpace::default()),
name,
);
Address { addressee_optic, address: ptr }
}
}
#[derive(Debug, Clone, Copy)]
pub struct OpaqueAddressLens;
impl<'ctx> MemoryOptic<'ctx> for OpaqueAddressLens {
type MemoryValue = BasicValueEnum<'ctx>;
fn get_llvm_type(&self, ctx: &'ctx Context) -> BasicTypeEnum<'ctx> {
ctx.i8_type().ptr_type(AddressSpace::default()).as_basic_type_enum()
}
}
impl<'ctx> OpaqueAddress<'ctx> {
pub fn store(&self, ctx: &CodeGenContext<'ctx, '_>, value: BasicValueEnum<'ctx>) {
}
}

View File

@ -21,8 +21,8 @@ impl<'ctx, T: BasicValue<'ctx>> OpticValue<'ctx> for T {
}
// TODO: The interface is unintuitive
pub trait Optic<'ctx>: Clone {
type Value: OpticValue<'ctx>;
pub trait MemoryOptic<'ctx>: Clone {
type MemoryValue: OpticValue<'ctx>;
fn get_llvm_type(&self, ctx: &'ctx Context) -> BasicTypeEnum<'ctx>;
@ -32,20 +32,20 @@ pub trait Optic<'ctx>: Clone {
}
}
pub trait Prism<'ctx>: Optic<'ctx> {
pub trait Prism<'ctx>: MemoryOptic<'ctx> {
// TODO: Return error if `review` fails
fn review<V: AnyValue<'ctx>>(&self, value: V) -> Self::Value;
fn review<V: AnyValue<'ctx>>(&self, value: V) -> Self::MemoryValue;
}
pub trait MemoryGetter<'ctx>: Optic<'ctx> {
pub trait MemoryGetter<'ctx>: MemoryOptic<'ctx> {
fn get(
&self,
ctx: &CodeGenContext<'ctx, '_>,
pointer: PointerValue<'ctx>,
name: &str,
) -> Self::Value;
) -> Self::MemoryValue;
}
pub trait MemorySetter<'ctx>: Optic<'ctx> {
fn set(&self, ctx: &CodeGenContext<'ctx, '_>, pointer: PointerValue<'ctx>, value: &Self::Value);
pub trait MemorySetter<'ctx>: MemoryOptic<'ctx> {
fn set(&self, ctx: &CodeGenContext<'ctx, '_>, pointer: PointerValue<'ctx>, value: &Self::MemoryValue);
}

View File

@ -9,7 +9,7 @@ use crate::codegen::CodeGenContext;
use super::{
address::Address,
core::{MemoryGetter, Optic},
core::{MemoryGetter, MemoryOptic},
};
// ((Memory, Pointer) -> ElementOptic::Value*)
@ -23,21 +23,21 @@ pub struct GepGetter<ElementOptic> {
pub element_optic: ElementOptic,
}
impl<'ctx, ElementOptic: Optic<'ctx>> Optic<'ctx> for GepGetter<ElementOptic> {
type Value = Address<'ctx, ElementOptic>;
impl<'ctx, ElementOptic: MemoryOptic<'ctx>> MemoryOptic<'ctx> for GepGetter<ElementOptic> {
type MemoryValue = 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> {
impl<'ctx, ElementOptic: MemoryOptic<'ctx>> MemoryGetter<'ctx> for GepGetter<ElementOptic> {
fn get(
&self,
ctx: &CodeGenContext<'ctx, '_>,
pointer: PointerValue<'ctx>,
name: &str,
) -> Self::Value {
) -> Self::MemoryValue {
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

View File

@ -6,7 +6,7 @@ use inkwell::{
use crate::codegen::CodeGenContext;
use super::core::{MemoryGetter, MemorySetter, Optic, Prism};
use super::core::{MemoryGetter, MemorySetter, MemoryOptic, Prism};
// NOTE: I wanted to make Int8Lens, Int16Lens, Int32Lens, with all
// having the trait IsIntLens, and implement `impl <S: IsIntLens> Optic<S> for T`,
@ -31,8 +31,8 @@ impl<'ctx> IntLens<'ctx> {
}
}
impl<'ctx> Optic<'ctx> for IntLens<'ctx> {
type Value = IntValue<'ctx>;
impl<'ctx> MemoryOptic<'ctx> for IntLens<'ctx> {
type MemoryValue = IntValue<'ctx>;
fn get_llvm_type(&self, _ctx: &'ctx Context) -> BasicTypeEnum<'ctx> {
self.0.as_basic_type_enum()
@ -40,7 +40,7 @@ impl<'ctx> Optic<'ctx> for IntLens<'ctx> {
}
impl<'ctx> Prism<'ctx> for IntLens<'ctx> {
fn review<V: AnyValue<'ctx>>(&self, value: V) -> Self::Value {
fn review<V: AnyValue<'ctx>>(&self, value: V) -> Self::MemoryValue {
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
@ -53,13 +53,13 @@ impl<'ctx> MemoryGetter<'ctx> for IntLens<'ctx> {
ctx: &CodeGenContext<'ctx, '_>,
pointer: PointerValue<'ctx>,
name: &str,
) -> Self::Value {
) -> Self::MemoryValue {
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) {
fn set(&self, ctx: &CodeGenContext<'ctx, '_>, pointer: PointerValue<'ctx>, int: &Self::MemoryValue) {
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();
}

View File

@ -1,5 +1,5 @@
use super::{
core::Optic,
core::MemoryOptic,
ixed::{BoundedIxed, Ixed},
};
@ -14,7 +14,7 @@ pub struct ArraySlice<'ctx, ElementOptic> {
pub base: Address<'ctx, ElementOptic>,
}
impl<'ctx, ElementOptic: Optic<'ctx>> Ixed<'ctx, ElementOptic> for ArraySlice<'ctx, ElementOptic> {
impl<'ctx, ElementOptic: MemoryOptic<'ctx>> Ixed<'ctx, ElementOptic> for ArraySlice<'ctx, ElementOptic> {
fn ix(
&self,
ctx: &CodeGenContext<'ctx, '_>,
@ -27,7 +27,7 @@ impl<'ctx, ElementOptic: Optic<'ctx>> Ixed<'ctx, ElementOptic> for ArraySlice<'c
}
}
impl<'ctx, ElementOptic: Optic<'ctx>> BoundedIxed<'ctx, ElementOptic>
impl<'ctx, ElementOptic: MemoryOptic<'ctx>> BoundedIxed<'ctx, ElementOptic>
for ArraySlice<'ctx, ElementOptic>
{
fn num_elements(&self, _ctx: &CodeGenContext<'ctx, '_>) -> IntValue<'ctx> {

View File

@ -9,7 +9,7 @@ use crate::codegen::CodeGenContext;
use super::{
address::Address,
core::{MemoryGetter, MemorySetter, Optic, OpticValue},
core::{MemoryGetter, MemorySetter, MemoryOptic, OpticValue},
gep::GepGetter,
};
@ -40,8 +40,8 @@ impl<'ctx, StructOptic> OpticValue<'ctx> for OpticalStructValue<'ctx, StructOpti
}
// TODO: check StructType
impl<'ctx, T: StructureOptic<'ctx>> Optic<'ctx> for T {
type Value = OpticalStructValue<'ctx, Self>;
impl<'ctx, T: StructureOptic<'ctx>> MemoryOptic<'ctx> for T {
type MemoryValue = OpticalStructValue<'ctx, Self>;
fn get_llvm_type(&self, ctx: &'ctx Context) -> BasicTypeEnum<'ctx> {
let mut builder = FieldBuilder::new(ctx, self.struct_name());
@ -59,7 +59,7 @@ impl<'ctx, T: StructureOptic<'ctx>> MemoryGetter<'ctx> for T {
ctx: &CodeGenContext<'ctx, '_>,
pointer: PointerValue<'ctx>,
name: &str,
) -> Self::Value {
) -> Self::MemoryValue {
OpticalStructValue {
optic: self.clone(),
llvm: ctx.builder.build_load(pointer, name).unwrap().into_struct_value(),
@ -72,14 +72,14 @@ impl<'ctx, T: StructureOptic<'ctx>> MemorySetter<'ctx> for T {
&self,
ctx: &CodeGenContext<'ctx, '_>,
pointer: PointerValue<'ctx>,
value: &Self::Value,
value: &Self::MemoryValue,
) {
ctx.builder.build_store(pointer, value.llvm).unwrap();
}
}
impl<'ctx, AddresseeOptic: StructureOptic<'ctx>> Address<'ctx, AddresseeOptic> {
pub fn focus<GetFieldGepFn, FieldElementOptic: Optic<'ctx>>(
pub fn focus<GetFieldGepFn, FieldElementOptic: MemoryOptic<'ctx>>(
&self,
ctx: &CodeGenContext<'ctx, '_>,
get_field_gep_fn: GetFieldGepFn,
@ -121,7 +121,7 @@ impl<'ctx> FieldBuilder<'ctx> {
index
}
pub fn add_field<ElementOptic: Optic<'ctx>>(
pub fn add_field<ElementOptic: MemoryOptic<'ctx>>(
&mut self,
name: &'static str,
element_optic: ElementOptic,