array codegen

This commit is contained in:
Edgar 2024-05-10 08:56:10 +02:00
parent 82fbd609c1
commit a6d4bee05a
7 changed files with 318 additions and 112 deletions

View file

@ -31,7 +31,7 @@ enum Commands {
#[arg(long)] #[arg(long)]
name: Option<String>, name: Option<String>,
/// Use a binary (application) template [default] /// Use a binary (application) template \[default\]
#[arg(long, group = "binary", default_value_t = true)] #[arg(long, group = "binary", default_value_t = true)]
bin: bool, bin: bool,

View file

@ -48,13 +48,20 @@ pub struct Ident {
pub span: Span, pub span: Span,
} }
// T: A + B
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Type { pub enum Type {
pub name: Ident, Basic {
pub generics: Vec<Type>, name: Ident,
pub qualifiers: Vec<TypeQualifier>, generics: Vec<Type>,
pub span: Span, qualifiers: Vec<TypeQualifier>,
span: Span,
},
Array {
of: Box<Self>,
size: Option<u32>,
qualifiers: Vec<TypeQualifier>,
span: Span,
},
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
@ -184,6 +191,7 @@ pub enum Expression {
Value(ValueExpr), Value(ValueExpr),
FnCall(FnCallExpr), FnCall(FnCallExpr),
StructInit(StructInitExpr), StructInit(StructInitExpr),
ArrayInit(ArrayInitExpr),
Unary(UnaryOp, Box<Self>), Unary(UnaryOp, Box<Self>),
Binary(Box<Self>, BinaryOp, Box<Self>), Binary(Box<Self>, BinaryOp, Box<Self>),
Deref(Box<Self>, Span), Deref(Box<Self>, Span),
@ -209,11 +217,18 @@ pub struct StructInitField {
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct StructInitExpr { pub struct StructInitExpr {
pub name: Type, pub name: Ident,
pub generics: Vec<Type>,
pub fields: BTreeMap<Ident, StructInitField>, pub fields: BTreeMap<Ident, StructInitField>,
pub span: Span, pub span: Span,
} }
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ArrayInitExpr {
pub data: Vec<Expression>,
pub span: Span,
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct FnCallExpr { pub struct FnCallExpr {
pub name: Ident, pub name: Ident,

View file

@ -21,7 +21,7 @@ use inkwell::{
values::{BasicValue, BasicValueEnum, PointerValue}, values::{BasicValue, BasicValueEnum, PointerValue},
AddressSpace, AddressSpace,
}; };
use ir::{LocalKind, ModuleBody, ProgramBody, TypeInfo, ValueTree}; use ir::{LocalKind, ModuleBody, Place, ProgramBody, TypeInfo, ValueTree};
use llvm_sys::debuginfo::LLVMDIFlagPublic; use llvm_sys::debuginfo::LLVMDIFlagPublic;
use tracing::{info, trace}; use tracing::{info, trace};
@ -160,7 +160,11 @@ pub fn compile(session: &Session, program: &ProgramBody) -> Result<PathBuf, Box<
compile_module(&mut module_ctx, *module_id); compile_module(&mut module_ctx, *module_id);
module_ctx.di_builder.finalize(); module_ctx.di_builder.finalize();
module_ctx.module.verify()?;
if let Err(e) = module_ctx.module.verify() {
eprintln!("{}", e.to_str()?);
Err(e)?;
}
// todo link modules together // todo link modules together
llvm_modules.push_back(module_ctx.module); llvm_modules.push_back(module_ctx.module);
@ -458,7 +462,44 @@ fn compile_fn(ctx: &ModuleCompileCtx, fn_id: DefId) -> Result<(), BuilderError>
_ => unreachable!(), _ => unreachable!(),
} }
} }
ir::PlaceElem::Index { .. } => todo!(), ir::PlaceElem::Index { local } => {
let value = compile_load_place(
ctx,
fn_id,
&locals,
&Place {
local: *local,
projection: Default::default(),
},
false,
)?;
ptr = unsafe {
ctx.builder.build_in_bounds_gep(
ptr.get_type(),
ptr,
&[
ctx.ctx.context.i32_type().const_int(0, false),
value.0.into_int_value(),
],
"constindex",
)?
};
}
ir::PlaceElem::ConstIndex { index } => {
ptr = unsafe {
ctx.builder.build_in_bounds_gep(
ptr.get_type(),
ptr,
&[ctx
.ctx
.context
.i32_type()
.const_int((*index) as u64, false)],
"constindex",
)?
};
}
} }
} }
@ -1034,6 +1075,7 @@ fn compile_rvalue<'ctx>(
} }
ir::PlaceElem::Field { .. } => todo!(), ir::PlaceElem::Field { .. } => todo!(),
ir::PlaceElem::Index { .. } => todo!(), ir::PlaceElem::Index { .. } => todo!(),
ir::PlaceElem::ConstIndex { .. } => todo!(),
} }
} }
@ -1224,6 +1266,7 @@ fn compile_load_place<'ctx>(
} }
} }
ir::PlaceElem::Index { .. } => todo!(), ir::PlaceElem::Index { .. } => todo!(),
ir::PlaceElem::ConstIndex { .. } => todo!(),
} }
} }
@ -1351,7 +1394,7 @@ fn compile_basic_type<'ctx>(
match &ty.kind { match &ty.kind {
ir::TypeKind::Unit => todo!(), ir::TypeKind::Unit => todo!(),
ir::TypeKind::Bool => ctx.ctx.context.bool_type().as_basic_type_enum(), ir::TypeKind::Bool => ctx.ctx.context.bool_type().as_basic_type_enum(),
ir::TypeKind::Char => ctx.ctx.context.i32_type().as_basic_type_enum(), ir::TypeKind::Char => ctx.ctx.context.i8_type().as_basic_type_enum(),
ir::TypeKind::Int(ty) => match ty { ir::TypeKind::Int(ty) => match ty {
ir::IntTy::I128 => ctx.ctx.context.i128_type().as_basic_type_enum(), ir::IntTy::I128 => ctx.ctx.context.i128_type().as_basic_type_enum(),
ir::IntTy::I64 => ctx.ctx.context.i64_type().as_basic_type_enum(), ir::IntTy::I64 => ctx.ctx.context.i64_type().as_basic_type_enum(),
@ -1437,6 +1480,26 @@ fn compile_basic_type<'ctx>(
.struct_type(&fields, false) .struct_type(&fields, false)
.as_basic_type_enum() .as_basic_type_enum()
} }
ir::TypeKind::Slice(inner, size) => {
let inner = compile_basic_type(ctx, inner);
if let Some(size) = size {
inner.array_type(*size).as_basic_type_enum()
} else {
ctx.ctx
.context
.struct_type(
&[
ctx.ctx
.context
.ptr_type(AddressSpace::default())
.as_basic_type_enum(),
ctx.ctx.context.i64_type().as_basic_type_enum(),
],
false,
)
.as_basic_type_enum()
}
}
} }
} }
@ -1631,5 +1694,52 @@ fn compile_debug_type<'ctx>(ctx: &ModuleCompileCtx<'ctx, '_>, ty: &ir::TypeInfo)
) )
.as_type() .as_type()
} }
ir::TypeKind::Slice(inner, size) => {
let real_ty = compile_basic_type(ctx, ty);
let inner_type = compile_debug_type(ctx, inner);
if let Some(size) = size {
ctx.di_builder
.create_array_type(
inner_type,
ctx.target_data.get_abi_size(&real_ty),
ctx.target_data.get_abi_alignment(&real_ty),
#[allow(clippy::single_range_in_vec_init)] // false positive
&[0..((*size) as i64)],
)
.as_type()
} else {
ctx.di_builder
.create_struct_type(
ctx.di_namespace,
"str",
ctx.di_unit.get_file(),
0,
ctx.target_data.get_bit_size(&real_ty),
ctx.target_data.get_abi_alignment(&real_ty),
0,
None,
&[
ctx.di_builder
.create_pointer_type(
name,
inner_type,
(ctx.target_data.get_pointer_byte_size(None) * 8).into(),
ctx.target_data.get_pointer_byte_size(None),
AddressSpace::default(),
)
.as_type(),
ctx.di_builder
.create_basic_type(name, 64, 0x7, LLVMDIFlagPublic)
.unwrap()
.as_type(),
],
0,
None,
"str",
)
.as_type()
}
}
} }
} }

View file

@ -60,7 +60,6 @@ pub fn link_binary(objects: &[PathBuf], output_filename: &Path) -> std::io::Resu
let mut args = vec![ let mut args = vec![
"-L/usr/local/lib", "-L/usr/local/lib",
"-L/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib", "-L/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib",
&input_path.display().to_string(),
]; ];
args.extend(objects.iter().map(|x| x.as_str())); args.extend(objects.iter().map(|x| x.as_str()));

View file

@ -262,6 +262,7 @@ pub enum TypeKind {
Ref(bool, Box<TypeInfo>), Ref(bool, Box<TypeInfo>),
// name for print purposes // name for print purposes
Struct(DefId, String), // todo, add generics Struct(DefId, String), // todo, add generics
Slice(Box<TypeInfo>, Option<u32>),
} }
impl TypeKind { impl TypeKind {
@ -308,6 +309,7 @@ impl TypeKind {
TypeKind::Ref(_, inner) => inner.kind.get_falsy_value(), TypeKind::Ref(_, inner) => inner.kind.get_falsy_value(),
TypeKind::Struct(_, _name) => todo!(), TypeKind::Struct(_, _name) => todo!(),
TypeKind::Str => todo!(), TypeKind::Str => todo!(),
TypeKind::Slice(_, _) => todo!(),
} }
} }
} }
@ -351,6 +353,15 @@ impl fmt::Display for TypeKind {
write!(f, "&{word} {}", inner.kind) write!(f, "&{word} {}", inner.kind)
} }
TypeKind::Struct(_, name) => write!(f, "{}", name), TypeKind::Struct(_, name) => write!(f, "{}", name),
TypeKind::Slice(inner, size) => {
let size = if let Some(size) = size {
format!("; {size}")
} else {
"".to_string()
};
write!(f, "[{}{size}]", inner.kind)
}
} }
} }
} }
@ -477,6 +488,7 @@ pub enum PlaceElem {
Deref, Deref,
Field { field_idx: usize }, Field { field_idx: usize },
Index { local: usize }, Index { local: usize },
ConstIndex { index: usize },
} }
impl TypeKind { impl TypeKind {

View file

@ -645,15 +645,16 @@ fn find_expr_type(builder: &mut BodyBuilder, info: &ast::Expression) -> Option<T
.get_module_body() .get_module_body()
.symbols .symbols
.structs .structs
.get(&info.name.name.name) .get(&info.name.name)
.expect("struct not found"); .expect("struct not found");
ir::TypeKind::Struct(id, info.name.name.name.clone()) ir::TypeKind::Struct(id, info.name.name.clone())
} }
ast::Expression::Cast(_, _new_ty, _) => { ast::Expression::Cast(_, _new_ty, _) => {
// checks? // checks?
todo!() todo!()
} }
ast::Expression::ArrayInit(_) => todo!(),
}) })
} }
@ -762,7 +763,7 @@ fn lower_expr(
.get_module_body() .get_module_body()
.symbols .symbols
.structs .structs
.get(&info.name.name.name) .get(&info.name.name)
.expect("struct not found"); .expect("struct not found");
let struct_body = builder.ctx.body.structs.get(&id).unwrap().clone(); let struct_body = builder.ctx.body.structs.get(&id).unwrap().clone();
let ty = TypeKind::Struct(id, struct_body.name.clone()); let ty = TypeKind::Struct(id, struct_body.name.clone());
@ -832,6 +833,45 @@ fn lower_expr(
(rvalue, kind, *span) (rvalue, kind, *span)
} }
ast::Expression::ArrayInit(info) => {
let ty = if let Some(type_hint) = type_hint {
type_hint.clone()
} else {
todo!()
};
let inner = if let TypeKind::Slice(inner, _) = &ty.kind {
inner
} else {
unreachable!()
};
let local = builder.add_temp_local(ty.kind.clone());
builder.statements.push(Statement {
span: None,
kind: StatementKind::StorageLive(local),
});
let place = Place {
local,
projection: Default::default(),
};
for (i, x) in info.data.iter().enumerate() {
let (value, _ty, span) = lower_expr(builder, x, Some(inner))?;
let mut place = place.clone();
place.projection.push(PlaceElem::ConstIndex { index: i });
builder.statements.push(Statement {
span: Some(span),
kind: StatementKind::Assign(place, value),
});
}
(
RValue::Use(Operand::Move(place), info.span),
ty.kind,
info.span,
)
}
}) })
} }
@ -1096,9 +1136,7 @@ fn lower_value(
span: None, span: None,
kind: ir::TypeKind::Char, kind: ir::TypeKind::Char,
}, },
kind: ir::ConstKind::Value(ir::ValueTree::Leaf(ir::ConstValue::U32( kind: ir::ConstKind::Value(ir::ValueTree::Leaf(ir::ConstValue::U8((*value) as u8))),
(*value) as u32,
))),
}), }),
TypeKind::Char, TypeKind::Char,
*span, *span,
@ -1475,82 +1513,106 @@ pub fn lower_type(
t: &ast::Type, t: &ast::Type,
module_id: DefId, module_id: DefId,
) -> Result<ir::TypeInfo, LoweringError> { ) -> Result<ir::TypeInfo, LoweringError> {
let mut ty = match t.name.name.as_str() { let (mut ty, qualifiers) = match t {
"()" => ir::TypeInfo { ast::Type::Basic {
span: Some(t.span), name,
kind: ir::TypeKind::Unit, generics: _,
}, qualifiers,
"u8" => ir::TypeInfo { span,
span: Some(t.span), } => {
kind: ir::TypeKind::Uint(ir::UintTy::U8), let ty = match name.name.as_str() {
}, "()" => ir::TypeInfo {
"u16" => ir::TypeInfo { span: Some(*span),
span: Some(t.span), kind: ir::TypeKind::Unit,
kind: ir::TypeKind::Uint(ir::UintTy::U16), },
}, "u8" => ir::TypeInfo {
"u32" => ir::TypeInfo { span: Some(*span),
span: Some(t.span), kind: ir::TypeKind::Uint(ir::UintTy::U8),
kind: ir::TypeKind::Uint(ir::UintTy::U32), },
}, "u16" => ir::TypeInfo {
"u64" => ir::TypeInfo { span: Some(*span),
span: Some(t.span), kind: ir::TypeKind::Uint(ir::UintTy::U16),
kind: ir::TypeKind::Uint(ir::UintTy::U64), },
}, "u32" => ir::TypeInfo {
"u128" => ir::TypeInfo { span: Some(*span),
span: Some(t.span), kind: ir::TypeKind::Uint(ir::UintTy::U32),
kind: ir::TypeKind::Uint(ir::UintTy::U128), },
}, "u64" => ir::TypeInfo {
"i8" => ir::TypeInfo { span: Some(*span),
span: Some(t.span), kind: ir::TypeKind::Uint(ir::UintTy::U64),
kind: ir::TypeKind::Int(ir::IntTy::I8), },
}, "u128" => ir::TypeInfo {
"i16" => ir::TypeInfo { span: Some(*span),
span: Some(t.span), kind: ir::TypeKind::Uint(ir::UintTy::U128),
kind: ir::TypeKind::Int(ir::IntTy::I16), },
}, "i8" => ir::TypeInfo {
"i32" => ir::TypeInfo { span: Some(*span),
span: Some(t.span), kind: ir::TypeKind::Int(ir::IntTy::I8),
kind: ir::TypeKind::Int(ir::IntTy::I32), },
}, "i16" => ir::TypeInfo {
"i64" => ir::TypeInfo { span: Some(*span),
span: Some(t.span), kind: ir::TypeKind::Int(ir::IntTy::I16),
kind: ir::TypeKind::Int(ir::IntTy::I64), },
}, "i32" => ir::TypeInfo {
"i128" => ir::TypeInfo { span: Some(*span),
span: Some(t.span), kind: ir::TypeKind::Int(ir::IntTy::I32),
kind: ir::TypeKind::Int(ir::IntTy::I128), },
}, "i64" => ir::TypeInfo {
"char" => ir::TypeInfo { span: Some(*span),
span: Some(t.span), kind: ir::TypeKind::Int(ir::IntTy::I64),
kind: ir::TypeKind::Char, },
}, "i128" => ir::TypeInfo {
"bool" => ir::TypeInfo { span: Some(*span),
span: Some(t.span), kind: ir::TypeKind::Int(ir::IntTy::I128),
kind: ir::TypeKind::Bool, },
}, "char" => ir::TypeInfo {
"str" => ir::TypeInfo { span: Some(*span),
span: Some(t.span), kind: ir::TypeKind::Char,
kind: ir::TypeKind::Str, },
}, "bool" => ir::TypeInfo {
other => { span: Some(*span),
let module = ctx.body.modules.get(&module_id).expect("module not found"); kind: ir::TypeKind::Bool,
if let Some(struct_id) = module.symbols.structs.get(other) { },
let struct_body = ctx.body.structs.get(struct_id).unwrap(); "str" => ir::TypeInfo {
ir::TypeInfo { span: Some(*span),
span: Some(struct_body.span), kind: ir::TypeKind::Str,
kind: TypeKind::Struct(*struct_id, struct_body.name.clone()), },
other => {
let module = ctx.body.modules.get(&module_id).expect("module not found");
if let Some(struct_id) = module.symbols.structs.get(other) {
let struct_body = ctx.body.structs.get(struct_id).unwrap();
ir::TypeInfo {
span: Some(struct_body.span),
kind: TypeKind::Struct(*struct_id, struct_body.name.clone()),
}
} else {
Err(LoweringError::UnrecognizedType {
span: name.span,
name: name.name.clone(),
file_id: module.file_id,
})?
}
} }
} else { };
Err(LoweringError::UnrecognizedType { (ty, qualifiers)
span: t.name.span, }
name: t.name.name.clone(), ast::Type::Array {
file_id: module.file_id, of,
})? size,
} qualifiers,
span,
} => {
let ty = ir::TypeInfo {
span: Some(*span),
kind: ir::TypeKind::Slice(Box::new(lower_type(ctx, of, module_id)?), *size),
};
(ty, qualifiers)
} }
}; };
for qualifier in t.qualifiers.iter().rev() { let span = ty.span;
for qualifier in qualifiers.iter().rev() {
let kind = match qualifier { let kind = match qualifier {
ast::TypeQualifier::Ref => TypeKind::Ref(false, Box::new(ty)), ast::TypeQualifier::Ref => TypeKind::Ref(false, Box::new(ty)),
ast::TypeQualifier::RefMut => TypeKind::Ref(true, Box::new(ty)), ast::TypeQualifier::RefMut => TypeKind::Ref(true, Box::new(ty)),
@ -1558,10 +1620,7 @@ pub fn lower_type(
ast::TypeQualifier::PtrMut => TypeKind::Ptr(true, Box::new(ty)), ast::TypeQualifier::PtrMut => TypeKind::Ptr(true, Box::new(ty)),
}; };
ty = TypeInfo { ty = TypeInfo { span, kind };
span: Some(t.span),
kind,
};
} }
Ok(ty) Ok(ty)

View file

@ -151,34 +151,36 @@ pub(crate) TypeQualifier: ast::TypeQualifier = {
} }
pub(crate) Type: ast::Type = { pub(crate) Type: ast::Type = {
<lo:@L> <qualifiers:TypeQualifier*> <name:Ident> <hi:@R> => ast::Type { <lo:@L> <qualifiers:TypeQualifier*> <name:Ident> <hi:@R> => ast::Type::Basic {
name, name,
generics: vec![], generics: vec![],
qualifiers, qualifiers,
span: ast::Span::new(lo, hi), span: ast::Span::new(lo, hi),
}, },
<lo:@L> <qualifiers:TypeQualifier*> <name:Ident> "<" <generics:Comma<Type>> ">" <hi:@R> => ast::Type { <lo:@L> <qualifiers:TypeQualifier*> <name:Ident> "<" <generics:Comma<Type>> ">" <hi:@R> => ast::Type::Basic {
name, name,
generics, generics,
qualifiers, qualifiers,
span: ast::Span::new(lo, hi), span: ast::Span::new(lo, hi),
}, },
<lo:@L> <qualifiers:TypeQualifier*> "[" <of:Type> "]" <hi:@R> => ast::Type::Array {
of: Box::new(of),
size: None,
qualifiers,
span: ast::Span::new(lo, hi),
},
<lo:@L> <qualifiers:TypeQualifier*> "[" <of:Type> ";" <size:"integer"> "]" <hi:@R> => ast::Type::Array {
of: Box::new(of),
size: Some(size.try_into().unwrap()),
qualifiers,
span: ast::Span::new(lo, hi),
},
} }
/// For things like A::<T> { a: value } /// For things like A::<T> { a: value }
pub(crate) IdentWithOptionalType: ast::Type = { pub(crate) IdentWithGenerics: (ast::Ident, Vec<ast::Type>) = {
<lo:@L> <name:Ident> <hi:@R> => ast::Type { <name:Ident> => (name, vec![]),
name, <lo:@L> <name:Ident> "::" "<" <generics:Comma<Type>> ">" <hi:@R> => (name, generics),
generics: vec![],
qualifiers: vec![],
span: ast::Span::new(lo, hi),
},
<lo:@L> <name:Ident> "::" "<" <generics:Comma<Type>> ">" <hi:@R> => ast::Type {
name,
generics,
qualifiers: vec![],
span: ast::Span::new(lo, hi),
},
} }
pub(crate) PathExpr: ast::PathExpr = { pub(crate) PathExpr: ast::PathExpr = {
@ -351,6 +353,7 @@ pub(crate) Expression: ast::Expression = {
#[precedence(level="5")] #[assoc(side="left")] #[precedence(level="5")] #[assoc(side="left")]
<lo:@L> <a:Expression> "as" <b: Type> <hi:@R> => ast::Expression::Cast(Box::new(a), b, ast::Span::new(lo, hi)), <lo:@L> <a:Expression> "as" <b: Type> <hi:@R> => ast::Expression::Cast(Box::new(a), b, ast::Span::new(lo, hi)),
"(" <StructInitExpr> ")" => ast::Expression::StructInit(<>), "(" <StructInitExpr> ")" => ast::Expression::StructInit(<>),
<ArrayInitExpr> => ast::Expression::ArrayInit(<>),
} }
pub BinaryFirstLvlOp: ast::BinaryOp = { pub BinaryFirstLvlOp: ast::BinaryOp = {
@ -412,13 +415,21 @@ pub(crate) StructInitField: (ast::Ident, ast::StructInitField) = {
} }
pub(crate) StructInitExpr: ast::StructInitExpr = { pub(crate) StructInitExpr: ast::StructInitExpr = {
<lo:@L> <name:IdentWithOptionalType> "{" <fields:Comma<StructInitField>> "}" <hi:@R> => ast::StructInitExpr { <lo:@L> <name:IdentWithGenerics> "{" <fields:Comma<StructInitField>> "}" <hi:@R> => ast::StructInitExpr {
name, name: name.0,
generics: name.1,
fields: fields.into_iter().collect(), fields: fields.into_iter().collect(),
span: ast::Span::new(lo, hi), span: ast::Span::new(lo, hi),
} }
} }
pub(crate) ArrayInitExpr: ast::ArrayInitExpr = {
<lo:@L> "[" <data:Comma<Expression>> "]" <hi:@R> => ast::ArrayInitExpr {
data: data.into_iter().collect(),
span: ast::Span::new(lo, hi),
}
}
pub(crate) FnParam: ast::FnParam = { pub(crate) FnParam: ast::FnParam = {
<lo:@L> <name:Ident> ":" <arg_type:Type> <hi:@R> => ast::FnParam { <lo:@L> <name:Ident> ":" <arg_type:Type> <hi:@R> => ast::FnParam {
name, name,