Skip to content

Commit

Permalink
Add function type
Browse files Browse the repository at this point in the history
  • Loading branch information
Y-Nak committed Nov 24, 2024
1 parent f7b4ac5 commit ff95f31
Show file tree
Hide file tree
Showing 16 changed files with 304 additions and 38 deletions.
2 changes: 1 addition & 1 deletion crates/interpreter/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,6 @@ dyn-clone = "1.0"

[dev-dependencies]
sonatina-parser = { path = "../parser" }
dir-test = "0.3"
dir-test = "0.4"
regex = "1.11"
once_cell = "1.20"
22 changes: 15 additions & 7 deletions crates/interpreter/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ impl State for Machine {
};

let addr = addr.as_usize();
let size = self.module_ctx.size_of(ty);
let size = self.module_ctx.size_of_unchecked(ty);
if addr + size > self.memory.len() {
return EvalValue::Undef;
}
Expand All @@ -181,7 +181,7 @@ impl State for Machine {
match ty.resolve_compound(&self.module_ctx).unwrap() {
CompoundTypeData::Array { elem: elem_ty, len } => {
let mut addr = addr;
let elem_size = self.module_ctx.size_of(elem_ty);
let elem_size = self.module_ctx.size_of_unchecked(elem_ty);
for _ in 0..len {
let elem_addr = EvalValue::Imm(Immediate::I256(I256::from(addr)));
let elem = self.load(elem_addr, elem_ty);
Expand All @@ -196,13 +196,17 @@ impl State for Machine {
let elem_addr = EvalValue::Imm(Immediate::I256(I256::from(addr)));
let field = self.load(elem_addr, field_ty);
fields.push(field);
addr += self.module_ctx.size_of(field_ty);
addr += self.module_ctx.size_of_unchecked(field_ty);
}
}

CompoundTypeData::Ptr(_) => {
unreachable!()
}

CompoundTypeData::Func { .. } => {
panic!("function type can't be placed in memory");
}
}

return EvalValue::Aggregate { fields, ty };
Expand All @@ -228,7 +232,7 @@ impl State for Machine {
panic!("udnef address in store")
};
let addr = addr.as_usize();
let size = self.module_ctx.size_of(ty);
let size = self.module_ctx.size_of_unchecked(ty);
if addr + size > self.memory.len() {
self.memory.resize(addr + size, 0);
}
Expand All @@ -241,7 +245,7 @@ impl State for Machine {
match ty.resolve_compound(&self.module_ctx).unwrap() {
CompoundTypeData::Array { elem: elem_ty, .. } => {
let mut addr = addr;
let elem_size = self.module_ctx.size_of(elem_ty);
let elem_size = self.module_ctx.size_of_unchecked(elem_ty);
for field in &fields {
let elem_addr = EvalValue::Imm(Immediate::I256(I256::from(addr)));
self.store(field.clone(), elem_addr, elem_ty);
Expand All @@ -254,13 +258,17 @@ impl State for Machine {
for (i, field_ty) in s.fields.into_iter().enumerate() {
let elem_addr = EvalValue::Imm(Immediate::I256(I256::from(addr)));
self.store(fields[i].clone(), elem_addr, field_ty);
addr += self.module_ctx.size_of(field_ty);
addr += self.module_ctx.size_of_unchecked(field_ty);
}
}

CompoundTypeData::Ptr(_) => {
unreachable!()
}

CompoundTypeData::Func { .. } => {
panic!("Function can't be stored in memory");
}
}

return EvalValue::Undef;
Expand Down Expand Up @@ -291,7 +299,7 @@ impl State for Machine {

fn alloca(&mut self, ty: Type) -> EvalValue {
let ptr = self.free_region;
self.free_region += self.module_ctx.size_of(ty);
self.free_region += self.module_ctx.size_of_unchecked(ty);
EvalValue::Imm(Immediate::I256(I256::from(ptr)))
}

Expand Down
4 changes: 4 additions & 0 deletions crates/ir/src/builder/module_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ impl ModuleBuilder {
self.ctx.with_ty_store_mut(|s| s.make_array(elem, len))
}

pub fn declare_func_type(&self, args: &[Type], ret_ty: Type) -> Type {
self.ctx.with_ty_store_mut(|s| s.make_func(args, ret_ty))
}

pub fn ptr_type(&self, ty: Type) -> Type {
self.ctx.with_ty_store_mut(|s| s.make_ptr(ty))
}
Expand Down
7 changes: 7 additions & 0 deletions crates/ir/src/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,13 @@ impl Signature {
self.ret_ty
}

pub fn func_ptr_type(&self, ctx: &ModuleCtx) -> Type {
ctx.with_ty_store_mut(|s| {
let func_ty = s.make_func(&self.args, self.ret_ty);
s.make_ptr(func_ty)
})
}

#[doc(hidden)]
pub fn set_ret_ty(&mut self, ty: Type) {
self.ret_ty = ty;
Expand Down
15 changes: 11 additions & 4 deletions crates/ir/src/interpret/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,13 @@ impl Interpret for Gep {

match cmpd_data {
CompoundTypeData::Array { elem, .. } => {
let elem_size = state.dfg().ctx.size_of(elem);
let elem_size = state.dfg().ctx.size_of_unchecked(elem);
offset += elem_size * idx_value;
current_ty = elem;
}

CompoundTypeData::Ptr(ty) => {
let size = state.dfg().ctx.size_of(ty);
let size = state.dfg().ctx.size_of_unchecked(ty);
offset += size * idx_value;
current_ty = ty;
}
Expand All @@ -78,13 +78,19 @@ impl Interpret for Gep {
let mut local_offset = 0;
for i in 0..idx_value {
let field_ty = s.fields[i];
let size = state.dfg().ctx.size_of(field_ty);
let align = state.dfg().ctx.align_of(field_ty);
let size = state.dfg().ctx.size_of_unchecked(field_ty);
let align = state.dfg().ctx.align_of_unchecked(field_ty);
local_offset += align_to(offset + size, align);
}
offset += local_offset;
current_ty = s.fields[idx_value];
}

CompoundTypeData::Func { .. } => {
panic!(
"Invalid GEP: indexing into a function type with more indices remaining"
);
}
}
}

Expand Down Expand Up @@ -115,6 +121,7 @@ impl Interpret for InsertValue {
CompoundTypeData::Array { len, .. } => len,
CompoundTypeData::Struct(s) => s.fields.len(),
CompoundTypeData::Ptr(_) => unreachable!(),
CompoundTypeData::Func { .. } => unreachable!(),
};
vec![EvalValue::Undef; len]
}
Expand Down
33 changes: 19 additions & 14 deletions crates/ir/src/isa/evm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::sync::LazyLock;

use sonatina_triple::{Architecture, TargetTriple};

use super::{Endian, Isa, TypeLayout};
use super::{Endian, Isa, TypeLayout, TypeLayoutError};
use crate::{inst::evm::inst_set::EvmInstSet, module::ModuleCtx, types::CompoundTypeData, Type};

#[derive(Debug, Clone, Copy)]
Expand Down Expand Up @@ -37,8 +37,8 @@ impl Isa for Evm {

struct EvmTypeLayout {}
impl TypeLayout for EvmTypeLayout {
fn size_of(&self, ty: crate::Type, ctx: &ModuleCtx) -> usize {
match ty {
fn size_of(&self, ty: crate::Type, ctx: &ModuleCtx) -> Result<usize, TypeLayoutError> {
let size = match ty {
Type::Unit => 0,
Type::I1 => 1,
Type::I8 => 1,
Expand All @@ -51,33 +51,38 @@ impl TypeLayout for EvmTypeLayout {
Type::Compound(cmpd) => {
let cmpd_data = ctx.with_ty_store(|s| s.resolve_compound(cmpd).clone());
match cmpd_data {
CompoundTypeData::Array { elem, len } => {
// TODO: alignment!
self.size_of(elem, ctx) * len
}
CompoundTypeData::Array { elem, len } => self.size_of(elem, ctx)? * len,

CompoundTypeData::Ptr(_) => 32,

CompoundTypeData::Struct(s) => {
if s.packed {
panic!("packed data is not supported yet!");
}
s.fields
.iter()
.copied()
.fold(0, |acc, ty| acc + self.size_of(ty, ctx))
let mut size = 0;
for &field in &s.fields {
size += self.size_of(field, ctx)?;
}

size
}

CompoundTypeData::Func { .. } => {
return Err(TypeLayoutError::UnrepresentableType(ty))
}
}
}
}
};

Ok(size)
}

fn pointer_repl(&self) -> Type {
Type::I256
}

fn align_of(&self, _ty: Type, _ctx: &ModuleCtx) -> usize {
1
fn align_of(&self, _ty: Type, _ctx: &ModuleCtx) -> Result<usize, TypeLayoutError> {
Ok(1)
}

fn endian(&self) -> Endian {
Expand Down
18 changes: 16 additions & 2 deletions crates/ir/src/isa/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,26 @@ pub trait Isa {
}

pub trait TypeLayout: Send + Sync {
fn size_of(&self, ty: Type, ctx: &ModuleCtx) -> usize;
fn align_of(&self, ty: Type, ctx: &ModuleCtx) -> usize;
fn size_of(&self, ty: Type, ctx: &ModuleCtx) -> Result<usize, TypeLayoutError>;
fn align_of(&self, ty: Type, ctx: &ModuleCtx) -> Result<usize, TypeLayoutError>;
fn pointer_repl(&self) -> Type;
fn endian(&self) -> Endian;
}

#[derive(Debug, Clone)]
pub enum TypeLayoutError {
/// The type is unsupported by the ISA.
UnsupportedType(Type),

/// An error indicating that the given type cannot be represented in memory.
///
/// This error occurs when attempting to compute the size or alignment of a
/// type that is abstract or has no concrete representation in memory.
/// For example, function types or unresolved abstract types cannot be
/// laid out in memory.
UnrepresentableType(Type),
}

#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum Endian {
Be,
Expand Down
20 changes: 17 additions & 3 deletions crates/ir/src/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use sonatina_triple::TargetTriple;

use crate::{
global_variable::GlobalVariableStore,
isa::{Endian, Isa, TypeLayout},
isa::{Endian, Isa, TypeLayout, TypeLayoutError},
types::TypeStore,
Function, InstSetBase, Signature, Type,
};
Expand Down Expand Up @@ -122,14 +122,22 @@ impl ModuleCtx {
}
}

pub fn size_of(&self, ty: Type) -> usize {
pub fn size_of(&self, ty: Type) -> Result<usize, TypeLayoutError> {
self.type_layout.size_of(ty, self)
}

pub fn align_of(&self, ty: Type) -> usize {
pub fn align_of(&self, ty: Type) -> Result<usize, TypeLayoutError> {
self.type_layout.align_of(ty, self)
}

pub fn size_of_unchecked(&self, ty: Type) -> usize {
self.size_of(ty).unwrap()
}

pub fn align_of_unchecked(&self, ty: Type) -> usize {
self.align_of(ty).unwrap()
}

pub fn func_sig<F, R>(&self, func_ref: FuncRef, f: F) -> R
where
F: FnOnce(&Signature) -> R,
Expand Down Expand Up @@ -175,3 +183,9 @@ impl ModuleCtx {
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct FuncRef(u32);
entity_impl!(FuncRef);

impl FuncRef {
pub fn as_ptr_ty(self, ctx: &ModuleCtx) -> Type {
ctx.func_sig(self, |sig| sig.func_ptr_type(ctx))
}
}
33 changes: 32 additions & 1 deletion crates/ir/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use std::{cmp, io};
use cranelift_entity::PrimaryMap;
use indexmap::IndexMap;
use rustc_hash::FxHashMap;
use smallvec::SmallVec;

use crate::{ir_writer::WriteWithModule, module::ModuleCtx};

Expand Down Expand Up @@ -40,6 +41,14 @@ impl TypeStore {
Type::Compound(compound)
}

pub fn make_func(&mut self, args: &[Type], ret_ty: Type) -> Type {
let compound = self.make_compound(CompoundTypeData::Func {
args: args.into(),
ret_ty,
});
Type::Compound(compound)
}

/// Returns `[StructDef]` if the given type is a struct type.
pub fn struct_def(&self, ty: Type) -> Option<&StructData> {
match ty {
Expand Down Expand Up @@ -230,15 +239,37 @@ impl WriteWithModule for CompoundType {
write!(w, "@{name}")
}
}

CompoundTypeData::Func { args, ret_ty: ret } => {
write!(w, "(")?;
let mut args = args.iter();
if let Some(arg_ty) = args.next() {
arg_ty.write(ctx, w)?;
};
for arg_ty in args {
write!(w, ", ")?;
arg_ty.write(ctx, w)?;
}

write!(w, ") -> ")?;
ret.write(ctx, w)
}
})
}
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum CompoundTypeData {
Array { elem: Type, len: usize },
Array {
elem: Type,
len: usize,
},
Ptr(Type),
Struct(StructData),
Func {
args: SmallVec<[Type; 8]>,
ret_ty: Type,
},
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
Expand Down
10 changes: 10 additions & 0 deletions crates/parser/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,15 @@ impl FromSyntax<Error> for Type {
}
Rule::unit_type => TypeKind::Unit,
Rule::struct_identifier => TypeKind::Struct(node.parse_str(Rule::struct_name)),
Rule::function_type => {
let args = node.descend_into(Rule::function_type_arg, |n| n.multi(Rule::type_name));
let ret_ty =
node.descend_into(Rule::function_ret_type, |n| n.single(Rule::type_name));
TypeKind::Func {
args,
ret_ty: Box::new(ret_ty),
}
}
_ => unreachable!(),
};
Type {
Expand All @@ -526,6 +535,7 @@ pub enum TypeKind {
Ptr(Box<Type>),
Array(Box<Type>, usize),
Struct(SmolStr),
Func { args: Vec<Type>, ret_ty: Box<Type> },
Unit,
Error,
}
Expand Down
Loading

0 comments on commit ff95f31

Please sign in to comment.