From 79c1243f0dc6fec79f5661633e4897c400103a68 Mon Sep 17 00:00:00 2001 From: Edgar Luque Date: Sat, 17 Feb 2024 21:31:15 +0100 Subject: [PATCH] struct field --- lib/edlang_codegen_llvm/src/codegen.rs | 94 +++++++++++++++----------- lib/edlang_ir/src/lib.rs | 5 +- lib/edlang_lowering/src/lib.rs | 42 ++++++------ 3 files changed, 79 insertions(+), 62 deletions(-) diff --git a/lib/edlang_codegen_llvm/src/codegen.rs b/lib/edlang_codegen_llvm/src/codegen.rs index 9170d4ad3..8ba6dc4f0 100644 --- a/lib/edlang_codegen_llvm/src/codegen.rs +++ b/lib/edlang_codegen_llvm/src/codegen.rs @@ -971,46 +971,9 @@ fn compile_load_operand<'ctx>( locals: &HashMap>, op: &ir::Operand, ) -> Result<(BasicValueEnum<'ctx>, TypeInfo), BuilderError> { - // todo: implement projection - let body = ctx.ctx.program.functions.get(&fn_id).unwrap(); Ok(match op { - ir::Operand::Copy(place) => { - let pointee_ty = compile_basic_type(ctx, &body.locals[place.local].ty); - let ptr = *locals.get(&place.local).unwrap(); - ( - ctx.builder.build_load(pointee_ty, ptr, "")?, - body.locals[place.local].ty.clone(), - ) - } - ir::Operand::Move(place) => { - let mut ptr = *locals.get(&place.local).unwrap(); - let mut local_ty = body.locals[place.local].ty.clone(); - - for proj in &place.projection { - match proj { - ir::PlaceElem::Deref => { - ptr = ctx - .builder - .build_load(compile_basic_type(ctx, &local_ty), ptr, "deref")? - .into_pointer_value(); - local_ty = match local_ty.kind { - ir::TypeKind::Ptr(inner) => *inner, - ir::TypeKind::Ref(_, inner) => *inner, - _ => unreachable!(), - } - } - ir::PlaceElem::Field { .. } => todo!(), - ir::PlaceElem::Index { .. } => todo!(), - } - } - - let pointee_ty = compile_basic_type(ctx, &local_ty); - - ( - ctx.builder.build_load(pointee_ty, ptr, "")?, - body.locals[place.local].ty.clone(), - ) - } + ir::Operand::Copy(place) => compile_load_place(ctx, fn_id, locals, place, true)?, + ir::Operand::Move(place) => compile_load_place(ctx, fn_id, locals, place, false)?, ir::Operand::Constant(data) => match &data.kind { ir::ConstKind::Value(value) => ( compile_value(ctx, value, &data.type_info)?, @@ -1021,6 +984,59 @@ fn compile_load_operand<'ctx>( }) } +fn compile_load_place<'ctx>( + ctx: &ModuleCompileCtx<'ctx, '_>, + fn_id: DefId, + locals: &HashMap>, + place: &ir::Place, + _is_copy: bool, +) -> Result<(BasicValueEnum<'ctx>, TypeInfo), BuilderError> { + let body = ctx.ctx.program.functions.get(&fn_id).unwrap(); + let mut ptr = *locals.get(&place.local).unwrap(); + let mut local_ty = body.locals[place.local].ty.clone(); + + for proj in &place.projection { + match proj { + ir::PlaceElem::Deref => { + ptr = ctx + .builder + .build_load(compile_basic_type(ctx, &local_ty), ptr, "deref")? + .into_pointer_value(); + local_ty = match local_ty.kind { + ir::TypeKind::Ptr(inner) => *inner, + ir::TypeKind::Ref(_, inner) => *inner, + _ => unreachable!(), + } + } + ir::PlaceElem::Field { field_idx } => { + local_ty = match local_ty.kind { + ir::TypeKind::Struct(id) => { + let struct_body = ctx.ctx.program.structs.get(&id).unwrap(); + let ty = struct_body.variants[*field_idx].ty.clone(); + let field_name = struct_body.variants[*field_idx].name.clone(); + ptr = ctx.builder.build_struct_gep( + compile_basic_type(ctx, &local_ty), + ptr, + (*field_idx).try_into().unwrap(), + &format!("ptr_field_{field_name}"), + )?; + ty + } + _ => unreachable!(), + } + } + ir::PlaceElem::Index { .. } => todo!(), + } + } + + let pointee_ty = compile_basic_type(ctx, &local_ty); + + Ok(( + ctx.builder.build_load(pointee_ty, ptr, "")?, + body.locals[place.local].ty.clone(), + )) +} + fn compile_value<'ctx>( ctx: &ModuleCompileCtx<'ctx, '_>, val: &ValueTree, diff --git a/lib/edlang_ir/src/lib.rs b/lib/edlang_ir/src/lib.rs index 49731e845..e2f08abc4 100644 --- a/lib/edlang_ir/src/lib.rs +++ b/lib/edlang_ir/src/lib.rs @@ -1,6 +1,6 @@ // Based on a cfg -use std::collections::{BTreeMap, HashSet}; +use std::collections::{BTreeMap, HashMap, HashSet}; use edlang_span::Span; use smallvec::SmallVec; @@ -94,6 +94,7 @@ pub struct AdtBody { pub is_pub: bool, pub name: String, pub variants: Vec, + pub name_to_idx: HashMap, pub span: Span, } @@ -359,7 +360,7 @@ pub struct Place { #[derive(Debug, Clone, Copy)] pub enum PlaceElem { Deref, - Field { field_idx: usize, type_info: usize }, + Field { field_idx: usize }, Index { local: usize }, } diff --git a/lib/edlang_lowering/src/lib.rs b/lib/edlang_lowering/src/lib.rs index 73dff9bb7..0457585ee 100644 --- a/lib/edlang_lowering/src/lib.rs +++ b/lib/edlang_lowering/src/lib.rs @@ -103,6 +103,7 @@ fn lower_struct(mut ctx: BuildCtx, info: &ast::Struct, module_id: DefId) -> Buil is_pub: true, // todo struct pub name: info.name.name.clone(), variants: Vec::new(), + name_to_idx: Default::default(), span: info.span, }; @@ -113,6 +114,8 @@ fn lower_struct(mut ctx: BuildCtx, info: &ast::Struct, module_id: DefId) -> Buil ty: lower_type(&ctx, &field.r#type, module_id), }; body.variants.push(variant); + body.name_to_idx + .insert(field.name.name.clone(), body.variants.len() - 1); } ctx.body.structs.insert(body.def_id, body); @@ -418,21 +421,6 @@ fn lower_let(builder: &mut BodyBuilder, info: &ast::LetStmt) { fn lower_assign(builder: &mut BodyBuilder, info: &ast::AssignStmt) { let (mut place, mut ty) = lower_path(builder, &info.name); - if let Some(PlaceElem::Deref) = place.projection.last() { - match &ty { - TypeKind::Ptr(inner) => { - ty = inner.kind.clone(); - } - TypeKind::Ref(is_mut, inner) => { - if !is_mut { - panic!("trying to mutate non mut ref"); - } - ty = inner.kind.clone(); - } - _ => unreachable!(), - } - } - for _ in 0..info.deref_times { match &ty { TypeKind::Ptr(inner) => { @@ -454,7 +442,7 @@ fn lower_assign(builder: &mut BodyBuilder, info: &ast::AssignStmt) { builder.statements.push(Statement { span: Some(info.name.first.span), kind: StatementKind::Assign(place, rvalue), - }) + }); } fn find_expr_type(builder: &mut BodyBuilder, info: &ast::Expression) -> Option { @@ -887,7 +875,6 @@ fn lower_value( }, ast::ValueExpr::Str { value: _, span: _ } => todo!(), ast::ValueExpr::Path(info) => { - // add deref info to path let (place, ty) = lower_path(builder, info); (Operand::Move(place), ty) } @@ -922,13 +909,26 @@ fn lower_path(builder: &mut BodyBuilder, info: &ast::PathExpr) -> (ir::Place, Ty .name_to_local .get(&info.first.name) .expect("local not found"); - let ty = builder.body.locals[local].ty.kind.clone(); - let projection = Vec::new(); + let mut ty = builder.body.locals[local].ty.kind.clone(); + let mut projection = Vec::new(); for extra in &info.extra { match extra { - ast::PathSegment::Field(_) => todo!(), + ast::PathSegment::Field(name) => { + // is while fine? auto deref + while let TypeKind::Ref(_, inner) = ty { + projection.push(PlaceElem::Deref); + ty = inner.kind; + } + + if let TypeKind::Struct(id) = ty { + let struct_body = builder.ctx.body.structs.get(&id).unwrap(); + let idx = *struct_body.name_to_idx.get(&name.name).unwrap(); + projection.push(PlaceElem::Field { field_idx: idx }); + ty = struct_body.variants[idx].ty.kind.clone(); + } + } ast::PathSegment::Index { .. } => todo!(), } } @@ -936,7 +936,7 @@ fn lower_path(builder: &mut BodyBuilder, info: &ast::PathExpr) -> (ir::Place, Ty ( Place { local, - projection: projection.into(), // todo, field array deref + projection: projection.into(), // todo, array }, ty, )