From 167a7cf001c5ca8c53519c212f5649e498cb2943 Mon Sep 17 00:00:00 2001 From: Edgar Date: Tue, 30 Jan 2024 14:05:14 -0300 Subject: [PATCH] prog --- Cargo.lock | 2 + lib/edlang_driver/Cargo.toml | 2 + lib/edlang_driver/src/lib.rs | 12 ++ lib/edlang_ir/src/lib.rs | 123 ++++++----- lib/edlang_ir/src/scalar_int.rs | 59 ++++++ lib/edlang_lowering/src/lib.rs | 354 +++++++++++++++++++++++++++++++- programs/simple.ed | 7 + 7 files changed, 504 insertions(+), 55 deletions(-) create mode 100644 lib/edlang_ir/src/scalar_int.rs create mode 100644 programs/simple.ed diff --git a/Cargo.lock b/Cargo.lock index cfb4fbfe9..b19491a77 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -563,6 +563,8 @@ dependencies = [ "edlang_ast", "edlang_check", "edlang_codegen_mlir", + "edlang_ir", + "edlang_lowering", "edlang_parser", "edlang_session", "tracing", diff --git a/lib/edlang_driver/Cargo.toml b/lib/edlang_driver/Cargo.toml index 1450aaea1..34eb1397e 100644 --- a/lib/edlang_driver/Cargo.toml +++ b/lib/edlang_driver/Cargo.toml @@ -17,6 +17,8 @@ color-eyre = "0.6.2" edlang_ast = { version = "0.1.0", path = "../edlang_ast" } edlang_check = { version = "0.1.0", path = "../edlang_check" } edlang_codegen_mlir = { version = "0.1.0", path = "../edlang_codegen_mlir" } +edlang_ir = { version = "0.1.0", path = "../edlang_ir" } +edlang_lowering = { version = "0.1.0", path = "../edlang_lowering" } edlang_parser = { version = "0.1.0", path = "../edlang_parser" } edlang_session = { version = "0.1.0", path = "../edlang_session" } tracing = { workspace = true } diff --git a/lib/edlang_driver/src/lib.rs b/lib/edlang_driver/src/lib.rs index 4d7499f23..0df95afdc 100644 --- a/lib/edlang_driver/src/lib.rs +++ b/lib/edlang_driver/src/lib.rs @@ -3,6 +3,7 @@ use std::{error::Error, path::PathBuf, time::Instant}; use ariadne::Source; use clap::Parser; use edlang_codegen_mlir::linker::{link_binary, link_shared_lib}; +use edlang_lowering::{lower_module, IdGenerator}; use edlang_session::{DebugInfo, OptLevel, Session}; #[derive(Parser, Debug)] @@ -24,6 +25,9 @@ pub struct CompilerArgs { #[arg(long, default_value_t = false)] ast: bool, + + #[arg(long, default_value_t = false)] + ir: bool, } pub fn main() -> Result<(), Box> { @@ -81,6 +85,14 @@ pub fn main() -> Result<(), Box> { return Ok(()); } + let mut gen = IdGenerator::new(0); + let ir = lower_module(&mut gen, &module); + + if args.ir { + println!("{:#?}", ir); + return Ok(()); + } + if args.mlir { println!("{}", edlang_codegen_mlir::compile_mlir(&session, &module)?); return Ok(()); diff --git a/lib/edlang_ir/src/lib.rs b/lib/edlang_ir/src/lib.rs index 33434b065..f15fffbee 100644 --- a/lib/edlang_ir/src/lib.rs +++ b/lib/edlang_ir/src/lib.rs @@ -1,59 +1,80 @@ // Based on a cfg +use std::collections::BTreeMap; + use edlang_span::Span; use smallvec::SmallVec; -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct Body { - pub locals: SmallVec<[Local; 4]>, - pub blocks: SmallVec<[BasicBlock; 8]>, - pub debug_info: SmallVec<[DebugInfo; 4]>, +pub mod scalar_int; + +#[derive(Debug, Clone)] +pub struct ModuleBody { + pub module_id: usize, + pub functions: BTreeMap, + pub modules: BTreeMap, + pub span: Span, } -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +/// Definition id. +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct DefId { + pub module_id: usize, + pub id: usize, +} + +#[derive(Debug, Clone)] +pub struct Body { + pub def_id: DefId, + pub is_pub: bool, + pub is_extern: bool, + pub ret_type: Option, + pub locals: SmallVec<[Local; 4]>, + pub blocks: SmallVec<[BasicBlock; 8]>, + pub fn_span: Span, +} + +#[derive(Debug, Clone)] pub struct DebugInfo { pub id: usize, pub span: Span, } -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Debug, Clone)] pub struct BasicBlock { pub id: usize, pub statements: SmallVec<[Statement; 8]>, pub terminator: Terminator, } -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Debug, Clone)] pub struct Local { - pub id: usize, pub mutable: bool, - pub debug_info: Option, - pub ty: usize, + pub span: Option, + pub ty: TypeInfo, pub kind: LocalKind, } -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)] +#[derive(Debug, Clone, Copy)] pub enum LocalKind { Temp, Arg, ReturnPointer, } -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Debug, Clone)] pub struct Statement { - pub id: usize, - pub debug_info: Option, + pub span: Option, pub kind: StatementKind, } -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Debug, Clone)] pub enum StatementKind { Assign(Place, RValue), StorageLive(usize), StorageDead(usize), } -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Debug, Clone)] pub enum Terminator { Target(usize), Return, @@ -68,24 +89,23 @@ pub enum Terminator { Unreachable, } -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Debug, Clone)] pub struct TypeInfo { - pub id: usize, - pub debug_info: Option, + pub span: Option, pub kind: TypeKind, } -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Debug, Clone)] pub enum TypeKind { Bool, Char, Int(IntTy), Uint(UintTy), - Float(FloatTY), + Float(FloatTy), FuncDef { name: String, args: Vec }, } -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Debug, Clone)] pub enum IntTy { I128, I64, @@ -95,7 +115,7 @@ pub enum IntTy { Isize, } -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Debug, Clone)] pub enum UintTy { U128, U64, @@ -105,57 +125,51 @@ pub enum UintTy { Usize, } -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub enum FloatTY { +#[derive(Debug, Clone)] +pub enum FloatTy { F32, F64, } -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Debug, Clone)] pub struct ConstData { - pub debug_info: Option, - pub type_info: usize, + pub span: Option, + pub type_info: TypeInfo, pub kind: ConstKind, } -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Debug, Clone)] pub enum ConstKind { Value(ValueTree), } -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)] -pub struct ScalarInt { - pub data: u128, - pub size: u8, -} - -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Debug, Clone)] pub enum ValueTree { - Leaf(ScalarInt), + Leaf(ConstValue), Branch(Vec), } -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Debug, Clone)] pub enum RValue { Use(Operand), BinOp(BinOp, Operand, Operand), UnOp(UnOp, Operand), } -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Debug, Clone)] pub enum Operand { Copy(Place), Move(Place), Constant(ConstData), } -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Debug, Clone)] pub struct Place { pub local: usize, pub projection: SmallVec<[PlaceElem; 1]>, } -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)] +#[derive(Debug, Clone, Copy)] pub enum PlaceElem { Deref, Field { field_idx: usize, type_info: usize }, @@ -204,11 +218,11 @@ impl TypeKind { } pub fn get_f32() -> Self { - Self::Float(FloatTY::F32) + Self::Float(FloatTy::F32) } pub fn get_f64() -> Self { - Self::Float(FloatTY::F64) + Self::Float(FloatTy::F64) } pub fn get_bool() -> Self { @@ -220,7 +234,7 @@ impl TypeKind { } } -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)] +#[derive(Debug, Clone, Copy)] pub enum BinOp { Add, Sub, @@ -241,8 +255,25 @@ pub enum BinOp { Offset, } -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)] +#[derive(Debug, Clone, Copy)] pub enum UnOp { Not, Neg, } + +#[derive(Debug, Clone, Copy)] +pub enum ConstValue { + Bool(bool), + I8(i8), + I16(i16), + I32(i32), + I64(i64), + I128(i128), + U8(u8), + U16(u16), + U32(u32), + U64(u64), + U128(u128), + F32(f32), + F64(f64), +} diff --git a/lib/edlang_ir/src/scalar_int.rs b/lib/edlang_ir/src/scalar_int.rs new file mode 100644 index 000000000..2ce1137be --- /dev/null +++ b/lib/edlang_ir/src/scalar_int.rs @@ -0,0 +1,59 @@ +use std::num::NonZeroU8; + +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)] +#[repr(packed(1))] +pub struct ScalarInt { + pub data: u128, + /// Size in bytes + pub size: NonZeroU8, +} + +impl ScalarInt { + /// Size in bytes + #[inline] + pub fn size(self) -> u64 { + self.size.get().into() + } + + #[inline] + pub fn try_from_int(i: impl Into, size_in_bytes: u64) -> Option { + let i = i.into(); + // `into` performed sign extension, we have to truncate + let truncated = truncate(size_in_bytes, i as u128); + if sign_extend(size_in_bytes, truncated) as i128 == i { + Some(Self { + data: truncated, + size: NonZeroU8::new(size_in_bytes as u8).unwrap(), + }) + } else { + None + } + } +} + +#[inline] +pub fn sign_extend(size: u64, value: u128) -> u128 { + let size = size * 8; + if size == 0 { + // Truncated until nothing is left. + return 0; + } + // Sign-extend it. + let shift = 128 - size; + // Shift the unsigned value to the left, then shift back to the right as signed + // (essentially fills with sign bit on the left). + (((value << shift) as i128) >> shift) as u128 +} + +/// Truncates `value` to `self` bits. +#[inline] +pub fn truncate(size: u64, value: u128) -> u128 { + let size = size * 8; + if size == 0 { + // Truncated until nothing is left. + return 0; + } + let shift = 128 - size; + // Truncate (shift left to drop out leftover values, shift right to fill with zeroes). + (value << shift) >> shift +} diff --git a/lib/edlang_lowering/src/lib.rs b/lib/edlang_lowering/src/lib.rs index 7d12d9af8..c4d5e9fae 100644 --- a/lib/edlang_lowering/src/lib.rs +++ b/lib/edlang_lowering/src/lib.rs @@ -1,14 +1,350 @@ -pub fn add(left: usize, right: usize) -> usize { - left + right +use std::collections::HashMap; + +use edlang_ast as ast; +use edlang_ir as ir; +use ir::{DefId, Local, Operand, Place, Statement, TypeInfo}; + +pub struct IdGenerator { + pub current_id: usize, + pub module_id: usize, } -#[cfg(test)] -mod tests { - use super::*; +impl IdGenerator { + pub const fn new(module_id: usize) -> Self { + Self { + current_id: 0, + module_id: 0, + } + } - #[test] - fn it_works() { - let result = add(2, 2); - assert_eq!(result, 4); + pub fn next_id(&mut self) -> usize { + self.current_id += 1; + self.current_id + } + + pub fn next_defid(&mut self) -> DefId { + let id = self.next_id(); + + DefId { + module_id: self.module_id, + id, + } + } +} + +pub fn lower_module(gen: &mut IdGenerator, module: &ast::Module) -> ir::ModuleBody { + let mut body = ir::ModuleBody { + module_id: gen.next_id(), + functions: Default::default(), + modules: Default::default(), + span: module.span, + }; + + let mut module_gen_id = IdGenerator::new(body.module_id); + + for stmt in &module.contents { + match stmt { + ast::ModuleStatement::Function(func) => { + let res = lower_function(&mut module_gen_id, func); + body.functions.insert(res.def_id, res); + } + ast::ModuleStatement::Constant(_) => todo!(), + ast::ModuleStatement::Struct(_) => todo!(), + ast::ModuleStatement::Module(_) => todo!(), + } + } + + body +} + +struct BodyBuilder { + pub body: ir::Body, + pub statements: Vec, + pub locals: HashMap, + pub ret_local: Option, +} + +fn lower_function(gen: &mut IdGenerator, func: &ast::Function) -> ir::Body { + let body = ir::Body { + def_id: gen.next_defid(), + ret_type: func.return_type.as_ref().map(|x| lower_type(gen, x)), + locals: Default::default(), + blocks: Default::default(), + fn_span: func.span, + is_pub: func.is_public, + is_extern: func.is_extern, + }; + + let mut builder = BodyBuilder { + body, + statements: Vec::new(), + locals: HashMap::new(), + ret_local: None, + }; + + // store args ret + + if let Some(ret_type) = func.return_type.as_ref() { + let ty = lower_type(gen, ret_type); + + let local = Local { + mutable: false, + span: None, + ty, + kind: ir::LocalKind::ReturnPointer, + }; + + builder.ret_local = Some(builder.body.locals.len()); + builder.body.locals.push(local); + } + + for arg in &func.params { + let ty = lower_type(gen, &arg.arg_type); + let local = Local { + mutable: false, + span: Some(arg.span), + ty, + kind: ir::LocalKind::Arg, + }; + builder + .locals + .insert(arg.name.name.clone(), builder.locals.len()); + builder.body.locals.push(local); + } + + for stmt in &func.body.body { + match stmt { + ast::Statement::Let(info) => lower_let(gen, &mut builder, info), + ast::Statement::Assign(_) => todo!(), + ast::Statement::For(_) => todo!(), + ast::Statement::While(_) => todo!(), + ast::Statement::If(_) => todo!(), + ast::Statement::Return(info) => lower_return(gen, &mut builder, info), + ast::Statement::FnCall(_) => todo!(), + } + } + + builder.body +} + +fn lower_let(gen: &mut IdGenerator, builder: &mut BodyBuilder, info: &ast::LetStmt) { + let rvalue = lower_expr(builder, &info.value, Some(&lower_type(gen, &info.r#type))); + + let local = ir::Local { + mutable: info.is_mut, + span: Some(info.span), + ty: lower_type(gen, &info.r#type), + kind: ir::LocalKind::Temp, + }; + + let id = builder.body.locals.len(); + builder.locals.insert(info.name.name.clone(), id); + builder.body.locals.push(local); + + builder.statements.push(ir::Statement { + span: Some(info.span), + kind: ir::StatementKind::StorageLive(id), + }); + builder.statements.push(ir::Statement { + span: Some(info.span), + kind: ir::StatementKind::Assign( + Place { + local: id, + projection: Default::default(), + }, + rvalue, + ), + }); +} + +fn lower_expr( + builder: &mut BodyBuilder, + info: &ast::Expression, + type_hint: Option<&TypeInfo>, +) -> ir::RValue { + match info { + ast::Expression::Value(info) => ir::RValue::Use(lower_value(builder, info, type_hint)), + ast::Expression::FnCall(_) => todo!(), + ast::Expression::Unary(_, _) => todo!(), + ast::Expression::Binary(_, _, _) => todo!(), + } +} + +fn lower_value( + builder: &mut BodyBuilder, + info: &ast::ValueExpr, + type_hint: Option<&TypeInfo>, +) -> Operand { + match info { + ast::ValueExpr::Bool { value, span } => ir::Operand::Constant(ir::ConstData { + span: Some(*span), + type_info: ir::TypeInfo { + span: None, + kind: ir::TypeKind::Bool, + }, + kind: ir::ConstKind::Value(ir::ValueTree::Leaf(ir::ConstValue::Bool(*value))), + }), + ast::ValueExpr::Char { value, span } => ir::Operand::Constant(ir::ConstData { + span: Some(*span), + type_info: ir::TypeInfo { + span: None, + kind: ir::TypeKind::Char, + }, + kind: ir::ConstKind::Value(ir::ValueTree::Leaf(ir::ConstValue::U32((*value) as u32))), + }), + ast::ValueExpr::Int { value, span } => { + let (ty, val) = match type_hint { + Some(type_hint) => match &type_hint.kind { + ir::TypeKind::Int(type_hint) => match type_hint { + ir::IntTy::I128 => ( + ir::TypeKind::Int(ir::IntTy::I128), + ir::ConstValue::I128((*value) as i128), + ), + ir::IntTy::I64 => ( + ir::TypeKind::Int(ir::IntTy::I64), + ir::ConstValue::I64((*value) as i64), + ), + ir::IntTy::I32 => ( + ir::TypeKind::Int(ir::IntTy::I32), + ir::ConstValue::I32((*value) as i32), + ), + ir::IntTy::I16 => ( + ir::TypeKind::Int(ir::IntTy::I16), + ir::ConstValue::I16((*value) as i16), + ), + ir::IntTy::I8 => ( + ir::TypeKind::Int(ir::IntTy::I8), + ir::ConstValue::I8((*value) as i8), + ), + ir::IntTy::Isize => todo!(), + }, + ir::TypeKind::Uint(type_hint) => match type_hint { + ir::UintTy::U128 => ( + ir::TypeKind::Uint(ir::UintTy::U128), + ir::ConstValue::U128(*value), + ), + ir::UintTy::U64 => ( + ir::TypeKind::Uint(ir::UintTy::U64), + ir::ConstValue::U64((*value) as u64), + ), + ir::UintTy::U32 => ( + ir::TypeKind::Uint(ir::UintTy::U32), + ir::ConstValue::U32((*value) as u32), + ), + ir::UintTy::U16 => ( + ir::TypeKind::Uint(ir::UintTy::U16), + ir::ConstValue::U16((*value) as u16), + ), + ir::UintTy::U8 => ( + ir::TypeKind::Uint(ir::UintTy::U8), + ir::ConstValue::U8((*value) as u8), + ), + _ => todo!(), + }, + _ => unreachable!(), + }, + None => todo!(), + }; + + ir::Operand::Constant(ir::ConstData { + span: Some(*span), + type_info: ir::TypeInfo { + span: None, + kind: ty, + }, + kind: ir::ConstKind::Value(ir::ValueTree::Leaf(val)), + }) + } + ast::ValueExpr::Float { value, span } => todo!(), + ast::ValueExpr::Str { value, span } => todo!(), + ast::ValueExpr::Path(info) => { + // add deref info to path + Operand::Move(lower_path(builder, info)) + } + } +} + +fn lower_return(gen: &mut IdGenerator, builder: &mut BodyBuilder, info: &ast::ReturnStmt) { + let ret_type = builder.body.ret_type.clone(); + if let Some(value) = &info.value { + let rvalue = lower_expr(builder, value, ret_type.as_ref()); + let ret_local = builder.ret_local.unwrap(); + + builder.statements.push(Statement { + span: Some(info.span), + kind: ir::StatementKind::Assign( + Place { + local: ret_local, + projection: Default::default(), + }, + rvalue, + ), + }) + } + + let statements = std::mem::take(&mut builder.statements); + + builder.body.blocks.push(ir::BasicBlock { + id: builder.body.blocks.len(), + statements: statements.into(), + terminator: ir::Terminator::Return, + }); +} + +fn lower_path(builder: &mut BodyBuilder, info: &ast::PathExpr) -> ir::Place { + let local = *builder + .locals + .get(&info.first.name) + .expect("local not found"); + + Place { + local, + projection: Default::default(), // todo, field array deref + } +} + +pub fn lower_type(gen: &mut IdGenerator, t: &ast::Type) -> ir::TypeInfo { + match t.name.name.as_str() { + "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), + }, + _ => todo!(), } } diff --git a/programs/simple.ed b/programs/simple.ed new file mode 100644 index 000000000..535da7143 --- /dev/null +++ b/programs/simple.ed @@ -0,0 +1,7 @@ +mod Main { + + fn main() -> i32 { + let x: i32 = 2; + return x; + } +}