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)]
name: Option<String>,
/// Use a binary (application) template [default]
/// Use a binary (application) template \[default\]
#[arg(long, group = "binary", default_value_t = true)]
bin: bool,

View file

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

View file

@ -21,7 +21,7 @@ use inkwell::{
values::{BasicValue, BasicValueEnum, PointerValue},
AddressSpace,
};
use ir::{LocalKind, ModuleBody, ProgramBody, TypeInfo, ValueTree};
use ir::{LocalKind, ModuleBody, Place, ProgramBody, TypeInfo, ValueTree};
use llvm_sys::debuginfo::LLVMDIFlagPublic;
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);
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
llvm_modules.push_back(module_ctx.module);
@ -458,7 +462,44 @@ fn compile_fn(ctx: &ModuleCompileCtx, fn_id: DefId) -> Result<(), BuilderError>
_ => 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::Index { .. } => todo!(),
ir::PlaceElem::ConstIndex { .. } => todo!(),
}
}
@ -1224,6 +1266,7 @@ fn compile_load_place<'ctx>(
}
}
ir::PlaceElem::Index { .. } => todo!(),
ir::PlaceElem::ConstIndex { .. } => todo!(),
}
}
@ -1351,7 +1394,7 @@ fn compile_basic_type<'ctx>(
match &ty.kind {
ir::TypeKind::Unit => todo!(),
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::IntTy::I128 => ctx.ctx.context.i128_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)
.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()
}
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![
"-L/usr/local/lib",
"-L/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib",
&input_path.display().to_string(),
];
args.extend(objects.iter().map(|x| x.as_str()));

View file

@ -262,6 +262,7 @@ pub enum TypeKind {
Ref(bool, Box<TypeInfo>),
// name for print purposes
Struct(DefId, String), // todo, add generics
Slice(Box<TypeInfo>, Option<u32>),
}
impl TypeKind {
@ -308,6 +309,7 @@ impl TypeKind {
TypeKind::Ref(_, inner) => inner.kind.get_falsy_value(),
TypeKind::Struct(_, _name) => todo!(),
TypeKind::Str => todo!(),
TypeKind::Slice(_, _) => todo!(),
}
}
}
@ -351,6 +353,15 @@ impl fmt::Display for TypeKind {
write!(f, "&{word} {}", inner.kind)
}
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,
Field { field_idx: usize },
Index { local: usize },
ConstIndex { index: usize },
}
impl TypeKind {

View file

@ -645,15 +645,16 @@ fn find_expr_type(builder: &mut BodyBuilder, info: &ast::Expression) -> Option<T
.get_module_body()
.symbols
.structs
.get(&info.name.name.name)
.get(&info.name.name)
.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, _) => {
// checks?
todo!()
}
ast::Expression::ArrayInit(_) => todo!(),
})
}
@ -762,7 +763,7 @@ fn lower_expr(
.get_module_body()
.symbols
.structs
.get(&info.name.name.name)
.get(&info.name.name)
.expect("struct not found");
let struct_body = builder.ctx.body.structs.get(&id).unwrap().clone();
let ty = TypeKind::Struct(id, struct_body.name.clone());
@ -832,6 +833,45 @@ fn lower_expr(
(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,
kind: ir::TypeKind::Char,
},
kind: ir::ConstKind::Value(ir::ValueTree::Leaf(ir::ConstValue::U32(
(*value) as u32,
))),
kind: ir::ConstKind::Value(ir::ValueTree::Leaf(ir::ConstValue::U8((*value) as u8))),
}),
TypeKind::Char,
*span,
@ -1475,82 +1513,106 @@ pub fn lower_type(
t: &ast::Type,
module_id: DefId,
) -> Result<ir::TypeInfo, LoweringError> {
let mut ty = match t.name.name.as_str() {
"()" => ir::TypeInfo {
span: Some(t.span),
kind: ir::TypeKind::Unit,
},
"u8" => ir::TypeInfo {
span: Some(t.span),
kind: ir::TypeKind::Uint(ir::UintTy::U8),
},
"u16" => ir::TypeInfo {
span: Some(t.span),
kind: ir::TypeKind::Uint(ir::UintTy::U16),
},
"u32" => ir::TypeInfo {
span: Some(t.span),
kind: ir::TypeKind::Uint(ir::UintTy::U32),
},
"u64" => ir::TypeInfo {
span: Some(t.span),
kind: ir::TypeKind::Uint(ir::UintTy::U64),
},
"u128" => ir::TypeInfo {
span: Some(t.span),
kind: ir::TypeKind::Uint(ir::UintTy::U128),
},
"i8" => ir::TypeInfo {
span: Some(t.span),
kind: ir::TypeKind::Int(ir::IntTy::I8),
},
"i16" => ir::TypeInfo {
span: Some(t.span),
kind: ir::TypeKind::Int(ir::IntTy::I16),
},
"i32" => ir::TypeInfo {
span: Some(t.span),
kind: ir::TypeKind::Int(ir::IntTy::I32),
},
"i64" => ir::TypeInfo {
span: Some(t.span),
kind: ir::TypeKind::Int(ir::IntTy::I64),
},
"i128" => ir::TypeInfo {
span: Some(t.span),
kind: ir::TypeKind::Int(ir::IntTy::I128),
},
"char" => ir::TypeInfo {
span: Some(t.span),
kind: ir::TypeKind::Char,
},
"bool" => ir::TypeInfo {
span: Some(t.span),
kind: ir::TypeKind::Bool,
},
"str" => ir::TypeInfo {
span: Some(t.span),
kind: ir::TypeKind::Str,
},
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()),
let (mut ty, qualifiers) = match t {
ast::Type::Basic {
name,
generics: _,
qualifiers,
span,
} => {
let ty = match name.name.as_str() {
"()" => ir::TypeInfo {
span: Some(*span),
kind: ir::TypeKind::Unit,
},
"u8" => ir::TypeInfo {
span: Some(*span),
kind: ir::TypeKind::Uint(ir::UintTy::U8),
},
"u16" => ir::TypeInfo {
span: Some(*span),
kind: ir::TypeKind::Uint(ir::UintTy::U16),
},
"u32" => ir::TypeInfo {
span: Some(*span),
kind: ir::TypeKind::Uint(ir::UintTy::U32),
},
"u64" => ir::TypeInfo {
span: Some(*span),
kind: ir::TypeKind::Uint(ir::UintTy::U64),
},
"u128" => ir::TypeInfo {
span: Some(*span),
kind: ir::TypeKind::Uint(ir::UintTy::U128),
},
"i8" => ir::TypeInfo {
span: Some(*span),
kind: ir::TypeKind::Int(ir::IntTy::I8),
},
"i16" => ir::TypeInfo {
span: Some(*span),
kind: ir::TypeKind::Int(ir::IntTy::I16),
},
"i32" => ir::TypeInfo {
span: Some(*span),
kind: ir::TypeKind::Int(ir::IntTy::I32),
},
"i64" => ir::TypeInfo {
span: Some(*span),
kind: ir::TypeKind::Int(ir::IntTy::I64),
},
"i128" => ir::TypeInfo {
span: Some(*span),
kind: ir::TypeKind::Int(ir::IntTy::I128),
},
"char" => ir::TypeInfo {
span: Some(*span),
kind: ir::TypeKind::Char,
},
"bool" => ir::TypeInfo {
span: Some(*span),
kind: ir::TypeKind::Bool,
},
"str" => ir::TypeInfo {
span: Some(*span),
kind: ir::TypeKind::Str,
},
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 {
span: t.name.span,
name: t.name.name.clone(),
file_id: module.file_id,
})?
}
};
(ty, qualifiers)
}
ast::Type::Array {
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 {
ast::TypeQualifier::Ref => TypeKind::Ref(false, 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)),
};
ty = TypeInfo {
span: Some(t.span),
kind,
};
ty = TypeInfo { span, kind };
}
Ok(ty)

View file

@ -151,34 +151,36 @@ pub(crate) TypeQualifier: ast::TypeQualifier = {
}
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,
generics: vec![],
qualifiers,
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,
generics,
qualifiers,
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 }
pub(crate) IdentWithOptionalType: ast::Type = {
<lo:@L> <name:Ident> <hi:@R> => ast::Type {
name,
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) IdentWithGenerics: (ast::Ident, Vec<ast::Type>) = {
<name:Ident> => (name, vec![]),
<lo:@L> <name:Ident> "::" "<" <generics:Comma<Type>> ">" <hi:@R> => (name, generics),
}
pub(crate) PathExpr: ast::PathExpr = {
@ -351,6 +353,7 @@ pub(crate) Expression: ast::Expression = {
#[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)),
"(" <StructInitExpr> ")" => ast::Expression::StructInit(<>),
<ArrayInitExpr> => ast::Expression::ArrayInit(<>),
}
pub BinaryFirstLvlOp: ast::BinaryOp = {
@ -412,13 +415,21 @@ pub(crate) StructInitField: (ast::Ident, ast::StructInitField) = {
}
pub(crate) StructInitExpr: ast::StructInitExpr = {
<lo:@L> <name:IdentWithOptionalType> "{" <fields:Comma<StructInitField>> "}" <hi:@R> => ast::StructInitExpr {
name,
<lo:@L> <name:IdentWithGenerics> "{" <fields:Comma<StructInitField>> "}" <hi:@R> => ast::StructInitExpr {
name: name.0,
generics: name.1,
fields: fields.into_iter().collect(),
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 = {
<lo:@L> <name:Ident> ":" <arg_type:Type> <hi:@R> => ast::FnParam {
name,