diff --git a/src/asm/amd64.rs b/src/asm/amd64.rs index 90c014c..88d7495 100644 --- a/src/asm/amd64.rs +++ b/src/asm/amd64.rs @@ -325,6 +325,16 @@ impl Register { rax, rbx, rcx, rdx, rsi, rdi, r8, r9, r10, r11, r12, r13, r14, r15, ] }; + + pub const SYSV_ARG_GPR: [Register; 6] = { + use Register::*; + [rdi, rsi, rdx, rcx, r8, r9] + }; + pub const SYSV_ARG_SSE: [Register; 8] = { + use Register::*; + [xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7] + }; + pub const SSE: [Register; 16] = { use Register::*; [ diff --git a/src/ast.rs b/src/ast.rs index 248f59d..d6be321 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -84,7 +84,7 @@ pub enum Tag { }, ArgumentList { /// [Argument] - parameters: Vec, + arguments: Vec, }, Argument { /// Ident @@ -348,6 +348,13 @@ impl Type { } } + pub fn return_type(&self) -> Option<&Type> { + match self { + Self::Fn { return_type, .. } => Some(&return_type), + _ => None, + } + } + pub fn equal_type(&self, rhs: &Self) -> Option { match (self, rhs) { (Self::ComptimeNumber, Self::Floating(_)) diff --git a/src/lexer.rs b/src/lexer.rs index 359fd65..8680105 100644 --- a/src/lexer.rs +++ b/src/lexer.rs @@ -181,6 +181,7 @@ impl<'a> TokenIterator<'a> { pub fn is_next_token(&mut self, token: Token) -> bool { self.clone().next_if(|item| item.token() == token).is_some() } + /// looks at the token 2 positions ahead and checks if it is equal to `token`. pub fn is_next_token2(&mut self, token: Token) -> bool { self.clone() .skip(1) diff --git a/src/lib.rs b/src/lib.rs index e63e914..74c8f58 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,6 +15,7 @@ pub mod ast; pub mod common; pub mod comptime; pub mod error; +//pub mod intern_pool; pub mod lexer; pub mod mir; pub mod parser; diff --git a/src/mir.rs b/src/mir.rs index bb4d63e..d5492b0 100644 --- a/src/mir.rs +++ b/src/mir.rs @@ -148,6 +148,10 @@ pub enum Inst { /// src, idx, GetElementPtr(Type), Parameter(Type), + /// src + Argument(Type), + /// start(func), end + Call(Type), /// lhs, rhs Add(Type), /// lhs, rhs @@ -237,9 +241,11 @@ impl Inst { | Inst::ConstantDoublePrecision | Inst::Cmp(_) | Inst::Branch(_) + | Inst::Argument(_) | Inst::Jump | Inst::Return => None, Inst::Phi2(ty) + | Inst::Call(ty) | Inst::GetElementPtr(ty) | Inst::Load(ty) | Inst::LoadRegister(ty) @@ -281,6 +287,7 @@ impl Inst { match self { Inst::Label | Inst::Branch(_) + | Inst::Argument(_) | Inst::Jump | Inst::ConstantBytes | Inst::ConstantByte @@ -325,6 +332,7 @@ impl Inst { | Inst::IsGe(_) | Inst::IsLe(_) | Inst::Phi2(_) + | Inst::Call(_) | Inst::ShiftLeft(_) | Inst::ShiftRightSigned(_) | Inst::ShiftRightUnsigned(_) => true, @@ -967,6 +975,33 @@ impl Mir { pub fn gen_param(&mut self, ty: Type) -> u32 { self.push(Inst::Parameter(ty), Data::none()) } + fn gen_arg(&mut self, ty: Type, src: u32) -> u32 { + self.push(Inst::Argument(ty), Data::node(src)) + } + pub fn gen_call( + &mut self, + ty: Type, + func: u32, + args: impl IntoIterator, + ) -> u32 { + let args = args + .into_iter() + .map(|(ty, mut arg)| { + if self.is_imm(arg) { + arg = self.gen_load_register(ty, arg); + } + (ty, arg) + }) + .collect::>(); + + let start = self.gen_arg(ty, func); + for (ty, arg) in args { + self.gen_arg(ty, arg); + } + let end = self.nodes.len() as u32; + + self.push(Inst::Call(ty), Data::binary(start, end)) + } /// truncates a value `src` of `mir::Type` `ty` to `bits` bits, while preserving the sign pub fn gen_truncate_integer(&mut self, src: u32, ty: Type, signed: bool, bits: u16) -> u32 { @@ -1217,6 +1252,17 @@ impl Mir { Inst::Parameter(ty) => { writeln!(w, "%{node} = param {ty}") } + Inst::Argument(_) => Ok(()), + Inst::Call(ty) => { + let (start, end) = data.as_binary(); + let func = self.data[start as usize].as_node(); + write!(w, "%{node} = {ty} call %{func} (")?; + for arg in (start + 1)..end { + let arg = self.data[arg as usize].as_node(); + write!(w, "%{arg}, ")?; + } + writeln!(w, ")") + } Inst::Add(ty) => { let (lhs, rhs) = data.as_binary(); writeln!(w, "%{node} = add {ty} %{lhs}, {ty} %{rhs}") @@ -2005,6 +2051,13 @@ impl Mir { let (src, _) = data.as_binary_noderefs(); references.insert((src, node)); } + Inst::Call(_) => { + let (lhs, rhs) = data.as_binary(); + for arg in lhs..rhs { + let arg = self.data[arg as usize].as_noderef(); + references.insert((arg, node)); + } + } // these instructions have no inputs // don't want a wildcard match here to make sure new instructions // are handled here when they are added. @@ -2020,6 +2073,7 @@ impl Mir { | Inst::ConstantSinglePrecision | Inst::ConstantDoublePrecision | Inst::ExternRef(_) + | Inst::Argument(_) | Inst::Alloca => {} } } @@ -2060,6 +2114,7 @@ impl Mir { Some(lhs) } Inst::Parameter(_) + | Inst::Call(_) | Inst::GetElementPtr(_) | Inst::LoadRegister(_) | Inst::Load(_) @@ -2088,6 +2143,7 @@ impl Mir { | Inst::Cmp(_) | Inst::Branch(_) | Inst::Phi2(_) + | Inst::Argument(_) | Inst::IsEq(_) | Inst::IsNeq(_) | Inst::IsGt(_) @@ -2188,6 +2244,7 @@ impl core::fmt::Display for ImmRegMem { #[derive(Debug, PartialEq, Eq)] enum RipRelative { + Reference(String), Label(Type, String), #[allow(dead_code)] Offset(Type, i32), @@ -2196,6 +2253,7 @@ enum RipRelative { impl RipRelative { fn ty(&self) -> Type { match self { + Self::Reference(_) => Type::QWord, RipRelative::Label(ty, _) => *ty, RipRelative::Offset(ty, _) => *ty, } @@ -2205,6 +2263,7 @@ impl RipRelative { impl core::fmt::Display for RipRelative { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { + Self::Reference(label) => write!(f, "{label}"), RipRelative::Label(ty, label) => write!(f, "{} ptr [rip + {label}]", ty.int_repr()), RipRelative::Offset(ty, offset) => { write!(f, "{} ptr [rip + {offset}]", ty.int_repr()) @@ -2251,7 +2310,7 @@ impl Function { let mut buf = String::new(); let w = &mut buf; let name = strings.get_str(self.name).to_owned(); - writeln!(w, ".{name}:")?; + writeln!(w, "{name}:")?; for (_, contents) in self.constants { writeln!(w, "{contents}")?; @@ -2337,15 +2396,12 @@ impl Function { writeln!(w, "push {reg}")?; } - let needs_frame = !saved_registers.is_empty() && self.stack_offset != 0; - - if needs_frame { - writeln!(w, "push rbp")?; - writeln!(w, "mov rbp, rsp")?; + writeln!(w, "push rbp")?; + writeln!(w, "mov rbp, rsp")?; + if self.stack_offset != 0 { writeln!(w, "sub rsp, {}", self.stack_offset)?; } - // zero rax because we might only return into some of it - writeln!(w, "test rax, rax")?; + write!(w, "{}", self.branches.remove(&NodeRef::MIN).unwrap())?; for (branch, content) in &self.branches { @@ -2355,13 +2411,11 @@ impl Function { writeln!(w, ".{name}__epilogue:")?; - if needs_frame { - writeln!(w, "mov rsp, rbp")?; - writeln!(w, "pop rbp")?; + writeln!(w, "mov rsp, rbp")?; + writeln!(w, "pop rbp")?; - for reg in saved_registers.iter().rev() { - writeln!(w, "pop {reg}")?; - } + for reg in saved_registers.iter().rev() { + writeln!(w, "pop {reg}")?; } writeln!(w, "ret")?; @@ -2411,6 +2465,7 @@ impl Mir { } Inst::GetElementPtr(ty) => liveness.get_register(node.into()).unwrap().into(), Inst::Parameter(ty) + | Inst::Call(ty) | Inst::Phi2(ty) | Inst::Add(ty) | Inst::Sub(ty) @@ -2453,11 +2508,11 @@ impl Mir { ImmRegMem::Mem(StackMem::new(offset, size)) } Inst::ExternRef(ty) => { - let ty = ty.unwrap_or(Type::QWord); - ImmRegMem::Rip(RipRelative::Label( - ty, - format!(".{}", strings.get_str(data.as_index())), - )) + // let ty = ty.unwrap_or(Type::QWord); + ImmRegMem::Rip(RipRelative::Reference(format!( + "{}", + strings.get_str(data.as_index()) + ))) } _ => { unreachable!() @@ -2623,6 +2678,74 @@ impl Mir { } } } + Inst::Argument(_) => {} + Inst::Call(ty) => { + let (start, end) = data.as_binary(); + let length = end - start + 1; + + let mut spilled_registers = vec![]; + + let mut gprs = Register::SYSV_ARG_GPR.into_iter().rev().collect::>(); + let mut sses = Register::SYSV_ARG_SSE.into_iter().rev().collect::>(); + + if liveness.is_register_in_use_at_node(NodeRef(node), Register::rax) { + writeln!(func.current_branch(), "push rax")?; + spilled_registers.push(Register::rax); + } + + for arg in (start + 1)..end { + variant!(self.nodes[arg as usize] => Inst::Argument(ty)); + let arg = self.data[arg as usize].as_node(); + let src = + self.node_as_operand(&liveness, &mapping, &mut func, strings, arg); + + if ty.is_floating() { + let reg = sses.pop().unwrap(); + if liveness.is_register_in_use_at_node(NodeRef(node), reg) { + writeln!(func.current_branch(), "push {reg}")?; + spilled_registers.push(reg); + } + + writeln!(func.current_branch(), "movss {reg}, {src}")?; + } else { + let reg = gprs.pop().unwrap(); + if liveness.is_register_in_use_at_node(NodeRef(node), reg) { + writeln!(func.current_branch(), "push {reg}")?; + spilled_registers.push(reg); + } + + let reg = ty.register_width(reg); + writeln!(func.current_branch(), "mov {reg}, {src}")?; + } + } + let f = self.data[start as usize].as_node(); + + let f = self.node_as_operand(&liveness, &mapping, &mut func, strings, f); + writeln!(func.current_branch(), "test rax, rax")?; + writeln!(func.current_branch(), "call {f}")?; + + let dst = ty.register_width(liveness.get_register(node.into()).unwrap()); + if ty.is_floating() { + if dst.parent_reg() != Register::xmm0 { + writeln!(func.current_branch(), "movss {dst}, xmm0")?; + } + } else { + if dst.parent_reg() != Register::rax { + writeln!( + func.current_branch(), + "mov {dst}, {}", + ty.register_width(Register::rax) + )?; + } + }; + + for reg in spilled_registers.into_iter().rev() { + if reg.parent_reg() == Register::rax { + continue; + } + writeln!(func.current_branch(), "pop {reg}")?; + } + } Inst::Add(ty) => { let dst = ty.register_width(liveness.get_register(node.into()).unwrap()); let (lhs, rhs) = data.as_binary(); diff --git a/src/parser.rs b/src/parser.rs index 5104e43..4aa7e0c 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -775,34 +775,34 @@ impl Tree { } /// PREFIX_EXPR <- - /// PRIMARY_EXPR - /// ! PRIMARY_EXPR - /// - PRIMARY_EXPR - /// & PRIMARY_EXPR - /// * PRIMARY_EXPR + /// POSTFIX_EXPR + /// ! POSTFIX_EXPR + /// - POSTFIX_EXPR + /// & POSTFIX_EXPR + /// * POSTFIX_EXPR pub fn parse_prefix_expr(&mut self, tokens: &mut TokenIterator) -> Result { match tokens.peek_token_or_err()?.token() { Token::Bang => { _ = tokens.next(); - let lhs = self.parse_primary_expr(tokens)?; + let lhs = self.parse_postfix_expr(tokens)?; Ok(self.nodes.push_tag(Tag::Not { lhs })) } Token::Minus => { _ = tokens.next(); - let lhs = self.parse_primary_expr(tokens)?; + let lhs = self.parse_postfix_expr(tokens)?; Ok(self.nodes.push_tag(Tag::Negate { lhs })) } Token::Ampersand => { _ = tokens.next(); - let lhs = self.parse_primary_expr(tokens)?; + let lhs = self.parse_postfix_expr(tokens)?; Ok(self.nodes.push_tag(Tag::Ref { lhs })) } Token::Star => { _ = tokens.next(); - let lhs = self.parse_primary_expr(tokens)?; + let lhs = self.parse_postfix_expr(tokens)?; Ok(self.nodes.push_tag(Tag::Deref { lhs })) } - _ => self.parse_primary_expr(tokens), + _ => self.parse_postfix_expr(tokens), } } @@ -823,9 +823,69 @@ impl Tree { } } + /// ARGUMENT <- + /// IDENT : EXPR + /// EXPR + pub fn parse_argument(&mut self, tokens: &mut TokenIterator) -> Result { + if tokens.is_next_token2(Token::Colon) { + let name = self.parse_ident(tokens)?; + _ = tokens.expect_token(Token::Colon)?; + let expr = self.parse_expr(tokens)?; + Ok(self.nodes.push_tag(Tag::Argument { + name: Some(name), + expr, + })) + } else { + let expr = self.parse_expr(tokens)?; + Ok(self.nodes.push_tag(Tag::Argument { name: None, expr })) + } + } + + /// ARGUMENT_LIST <- + /// ARGUMENT + /// ARGUMENT_LIST , ARGUMENT + pub fn parse_argument_list(&mut self, tokens: &mut TokenIterator) -> Result { + let mut arguments = Vec::new(); + + loop { + // PARAMETER + arguments.push(self.parse_argument(tokens)?); + // COMMA + if !tokens.is_next_token(Token::Comma) { + break; + } + if tokens.is_next_token2(Token::CloseParens) { + break; + } + // skip comma + _ = tokens.next(); + } + + Ok(self.nodes.push_tag(Tag::ArgumentList { arguments })) + } + + /// POSTFIX_EXPR <- + /// PRIMARY_EXPR + /// PRIMARY_EXPR ( ) + /// PRIMARY_EXPR ( ARGUMENT_LIST ) pub fn parse_postfix_expr(&mut self, tokens: &mut TokenIterator) -> Result { - // TODO - self.parse_primary_expr(tokens) + let lhs = self.parse_primary_expr(tokens)?; + + if tokens.eat_token(Token::OpenParens).is_some() { + let rhs = if !tokens.is_next_token(Token::CloseParens) { + let arguments = self.parse_argument_list(tokens)?; + _ = tokens.eat_token(Token::Comma); + Some(arguments) + } else { + None + }; + + _ = tokens.expect_token(Token::CloseParens)?; + + Ok(self.nodes.push_tag(Tag::CallExpr { lhs, rhs })) + } else { + Ok(lhs) + } } /// PRIMARY_EXPR <- @@ -1121,7 +1181,9 @@ impl Tree { vec![lhs] } } - Tag::ArgumentList { parameters } => parameters.clone(), + Tag::ArgumentList { + arguments: parameters, + } => parameters.clone(), &Tag::Argument { name, expr } => { if let Some(name) = name { vec![name, expr] @@ -1323,9 +1385,36 @@ impl Tree { writeln!(writer, ");")?; Ok(()) } - Tag::CallExpr { .. } => todo!(), - Tag::ArgumentList { .. } => todo!(), - Tag::Argument { .. } => todo!(), + Tag::CallExpr { lhs, rhs } => { + self.render_node(writer, lhs, indent)?; + if let Some(rhs) = rhs { + self.render_node(writer, rhs, indent)?; + writeln_indented!(indent, writer, "%{node} = call (%{lhs})(%{rhs})") + } else { + writeln_indented!(indent, writer, "%{node} = call (%{lhs})()") + } + } + Tag::ArgumentList { arguments } => { + writeln_indented!(indent, writer, "%{} = ArgumentList [", node.get())?; + for args in arguments { + self.render_node(writer, args, indent + 1)?; + } + writeln_indented!(indent, writer, "]") + } + Tag::Argument { name, expr } => { + if let Some(name) = name { + writeln_indented!( + indent, + writer, + "%{} = {}: %{expr},", + node.get(), + self.get_ident_str(name).unwrap(), + ) + } else { + writeln_indented!(indent, writer, "%{} = %{expr},", node.get(),) + } + } + Tag::ExplicitCast { lhs, typename } => { self.render_node(writer, lhs, indent)?; writeln_indented!( @@ -1788,7 +1877,7 @@ impl Tree { ty } - Tag::CallExpr { lhs, .. } => self.type_of_node(*lhs), + Tag::CallExpr { lhs, .. } => self.type_of_node(*lhs).return_type().unwrap().clone(), Tag::ExplicitCast { typename, .. } => self.type_of_node(*typename), Tag::Deref { lhs } => self.type_of_node(*lhs).remove_ptr().unwrap(), Tag::Ref { lhs } => self.type_of_node(*lhs).into_ptr(), @@ -2340,7 +2429,9 @@ impl Tree { Tag::DeclRef(_) => todo!(), Tag::GlobalRef(_) => todo!(), Tag::CallExpr { lhs, rhs } => todo!(), - Tag::ArgumentList { parameters } => todo!(), + Tag::ArgumentList { + arguments: parameters, + } => todo!(), Tag::Argument { name, expr } => todo!(), Tag::ExplicitCast { lhs, typename } => todo!(), Tag::Deref { lhs } => todo!(), diff --git a/src/triples.rs b/src/triples.rs index a7526fc..91c9cf2 100644 --- a/src/triples.rs +++ b/src/triples.rs @@ -2,14 +2,14 @@ use std::{ cmp::Ordering, - collections::{BTreeMap, BTreeSet, HashMap}, + collections::{BTreeMap, BTreeSet, HashMap, VecDeque}, }; use crate::{ ast::{IntegralType, Node as AstNode, Tag, Type}, parser::Tree, string_table::{ImmOrIndex, Index as StringsIndex, StringTable}, - variant, writeln_indented, + variant, write_indented, writeln_indented, }; type Node = u32; @@ -119,6 +119,7 @@ impl From<&Type> for Type2 { crate::ast::FloatingType::Binary64 => Type2::Binary64, }, Type::Pointer { .. } => Type2::Pointer, + Type::Fn { .. } => Type2::Pointer, _ => { unimplemented!("conversion from {value:?} to triples type not implemented") } @@ -130,10 +131,18 @@ impl From<&Type> for Type2 { pub enum Inst { /// index Label, + /// ast-node -> index + ExternRef(Type2), /// index FunctionStart, /// None FunctionEnd, // marker + /// lhs + Argument(Type2), + InlineType(Type2), + /// list of arguments + /// start, (inlinetype)end + Call(Node), /// Value /// lhs GlobalConstant(StringsIndex, Type2), @@ -143,8 +152,6 @@ pub enum Inst { ConstantU64, /// index ConstantMultiByte, - /// ast-node - ExternRef, /// size, align Alloca, /// src @@ -286,6 +293,7 @@ pub struct IRBuilder<'tree, 'ir> { tree: &'tree mut Tree, type_map: HashMap, lookup: HashMap, + fixup: Vec, } impl core::ops::Index for IR { @@ -303,6 +311,7 @@ impl<'tree, 'ir> IRBuilder<'tree, 'ir> { tree, type_map: HashMap::new(), lookup: HashMap::new(), + fixup: vec![], } } @@ -382,6 +391,40 @@ impl<'tree, 'ir> IRBuilder<'tree, 'ir> { self.ir.push(Inst::FunctionEnd, None) } + Tag::CallExpr { lhs, rhs } => { + let ty = self.tree.type_of_node(*lhs).return_type().unwrap().clone(); + let args = + if let Some(args) = *rhs { + variant!( + self.tree.nodes.get_node(args) => Tag::ArgumentList { arguments } + ); + + let args = arguments.clone().iter().map(|arg| { + variant!(*self.tree.nodes.get_node(*arg) => Tag::Argument { expr ,..}); + (self.visit(expr), self.tree.type_of_node(expr)) + }).collect::>(); + + let start = self.ir.nodes.len(); + for (arg, ty) in args { + _ = self + .ir + .push(Inst::Argument(ty.into()), Some(Data::lhs(arg))); + } + let end = self.ir.nodes.len(); + + Some((start as u32, end as u32)) + } else { + None + }; + let (start, end) = + args.unwrap_or((self.ir.nodes.len() as u32, self.ir.nodes.len() as u32)); + self.ir.push(Inst::InlineType(ty.into()), None); + + let func = self.visit(*lhs); + + self.ir + .push(Inst::Call(func), Some(Data::new(start, end + 1))) + } Tag::Block { statements, trailing_expr, @@ -431,14 +474,11 @@ impl<'tree, 'ir> IRBuilder<'tree, 'ir> { global } Tag::GlobalRef(decl) => { - let node = match self.lookup.get_mut(decl) { - Some(NodeOrList::Node(decl)) => *decl, - lookup => { - println!("lookup for ast decl %{}", decl.get()); - println!("{lookup:?}"); - panic!("should not have any unresolved lookups") - } - }; + let ty = self.tree.type_of_node(*decl); + let node = self + .ir + .push(Inst::ExternRef(ty.into()), Some(Data::lhs(decl.get()))); + self.fixup.push(node); node } Tag::DeclRef(decl) => match self.lookup.get_mut(decl) { @@ -680,6 +720,27 @@ impl IR { for node in &global_decls { builder.visit(*node); } + + for &fix in builder.fixup.iter() { + let ast_node = builder.ir.data[fix as usize].unwrap().lhs; + + let idx = match builder.tree.nodes.get_node(AstNode::new(ast_node).unwrap()) { + Tag::FunctionDecl { proto, .. } => { + variant!(builder.tree.nodes.get_node(*proto) => Tag::FunctionProto { name,..}); + variant!(builder.tree.nodes.get_node(*name) => Tag::Ident { name }); + *name + } + Tag::GlobalDecl { name, .. } => { + variant!(builder.tree.nodes.get_node(*name) => Tag::Ident { name }); + *name + } + _ => { + unreachable!() + } + }; + builder.ir.data[fix as usize] = Some(idx.into()); + } + builder } } @@ -718,6 +779,25 @@ impl<'tree, 'ir> IRBuilder<'tree, 'ir> { align )?; } + Inst::Argument(ty) => { + let lhs = data.lhs; + writeln_indented!(indent, w, "%{node} = argument {ty} %{lhs}",)?; + } + Inst::InlineType(_) => {} + Inst::Call(func) => { + let (start, end) = data.as_lhs_rhs(); + variant!(&self.ir.nodes[end as usize -1] => Inst::InlineType(ty)); + + write_indented!(indent, w, "%{node} = {ty} call %{func}(",)?; + if start + 1 == end { + } else { + for arg in start..(end - 1) { + let arg = self.ir.data[arg as usize].unwrap().lhs; + write_indented!(indent, w, "%{arg}, ")?; + } + } + writeln_indented!(indent, w, ")")?; + } Inst::ConstantU32 => { writeln_indented!(indent, w, "%{} = const i32 {}", node, data.as_u32())?; } @@ -821,9 +901,14 @@ impl<'tree, 'ir> IRBuilder<'tree, 'ir> { let (src, dst) = data.as_lhs_rhs(); writeln_indented!(indent, w, "%{} = store {ty}, ptr %{dst}, %{src}", node)?; } - Inst::ExternRef => { - let ast = data.lhs; - writeln_indented!(indent, w, "%{} = extern reference ast-node %{}", node, ast)?; + Inst::ExternRef(ty) => { + let idx = data.as_index(); + writeln_indented!( + indent, + w, + "%{node} = extern reference {ty} '{}'", + self.tree.strings.get_str(idx) + )?; } Inst::Branch(condition) => { let (lhs, rhs) = data.as_lhs_rhs(); @@ -1169,6 +1254,7 @@ impl<'a> IrToMirMapping<'a> { match self.ir.nodes[ir as usize] { Inst::GlobalConstant(name, ty) => { + eprintln!("does this even get hit anymore???????????????????//"); let ext = mir::NodeRef(mir.gen_extern(Some(ty.mir_type()), name)); self.insert(ir, ext); Some(ext) @@ -1291,7 +1377,6 @@ impl<'a> MirBuilder<'a> { } } } - Inst::ExternRef => todo!(), Inst::Alloca => { let (l, r) = data.unwrap().as_lhs_rhs(); mir.gen_alloca(l, r) @@ -1674,6 +1759,25 @@ impl<'a> MirBuilder<'a> { br } + Inst::Call(func) => { + let f = mapping.get(&mut mir, func).unwrap().0; + + let ir = self.ir.ir; + let (start, end) = data.unwrap().as_lhs_rhs(); + + variant!(&ir.nodes[end as usize -1] => Inst::InlineType(ty)); + + let args = (start..(end - 1)) + .map(|arg| { + variant!(&ir.nodes[arg as usize] => Inst::Argument(ty)); + let arg = ir.data[arg as usize].unwrap().lhs; + let arg = mapping.get(&mut mir, arg).unwrap().0; + (ty.mir_type(), arg) + }) + .collect::>(); + + mir.gen_call(ty.mir_type(), f, args) + } Inst::Phi2(ty) => { let (src, dst) = data.unwrap().as_lhs_rhs(); let lhs = mapping.get(&mut mir, src).unwrap().0; @@ -1686,6 +1790,12 @@ impl<'a> MirBuilder<'a> { ext } + Inst::Argument(_) | Inst::InlineType(_) => { + continue; + } + Inst::ExternRef(ty) => { + mir.gen_extern(Some(ty.mir_type()), data.unwrap().as_index()) + } #[allow(unreachable_patterns)] _ => { eprintln!("ir inst {inst:?} not supported in mir translation"); diff --git a/tests/legal/call.sea b/tests/legal/call.sea new file mode 100644 index 0000000..6dc585a --- /dev/null +++ b/tests/legal/call.sea @@ -0,0 +1,11 @@ + +fn square_of_greater(a: i32, b: i32) -> i32 { + if (a > b) + a * a + else + b * b +} + +fn main() -> i32 { + return square_of_greater(2i32 + 2, 5i32); +} \ No newline at end of file diff --git a/tests/legal/global_var.sea b/tests/legal/global_var.sea new file mode 100644 index 0000000..1016bb2 --- /dev/null +++ b/tests/legal/global_var.sea @@ -0,0 +1,5 @@ +fn main() -> i32 { + return RANDOM; +} + +const RANDOM: i32 = 4 + (1 << 3);