calling functions

This commit is contained in:
Janis 2024-09-02 16:03:12 +02:00
parent 4424ef875d
commit 568c3b2fa4
9 changed files with 413 additions and 54 deletions

View file

@ -325,6 +325,16 @@ impl Register {
rax, rbx, rcx, rdx, rsi, rdi, r8, r9, r10, r11, r12, r13, r14, r15, 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] = { pub const SSE: [Register; 16] = {
use Register::*; use Register::*;
[ [

View file

@ -84,7 +84,7 @@ pub enum Tag {
}, },
ArgumentList { ArgumentList {
/// [Argument] /// [Argument]
parameters: Vec<Node>, arguments: Vec<Node>,
}, },
Argument { Argument {
/// Ident /// 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<Type> { pub fn equal_type(&self, rhs: &Self) -> Option<Type> {
match (self, rhs) { match (self, rhs) {
(Self::ComptimeNumber, Self::Floating(_)) (Self::ComptimeNumber, Self::Floating(_))

View file

@ -181,6 +181,7 @@ impl<'a> TokenIterator<'a> {
pub fn is_next_token(&mut self, token: Token) -> bool { pub fn is_next_token(&mut self, token: Token) -> bool {
self.clone().next_if(|item| item.token() == token).is_some() 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 { pub fn is_next_token2(&mut self, token: Token) -> bool {
self.clone() self.clone()
.skip(1) .skip(1)

View file

@ -15,6 +15,7 @@ pub mod ast;
pub mod common; pub mod common;
pub mod comptime; pub mod comptime;
pub mod error; pub mod error;
//pub mod intern_pool;
pub mod lexer; pub mod lexer;
pub mod mir; pub mod mir;
pub mod parser; pub mod parser;

View file

@ -148,6 +148,10 @@ pub enum Inst {
/// src, idx, /// src, idx,
GetElementPtr(Type), GetElementPtr(Type),
Parameter(Type), Parameter(Type),
/// src
Argument(Type),
/// start(func), end
Call(Type),
/// lhs, rhs /// lhs, rhs
Add(Type), Add(Type),
/// lhs, rhs /// lhs, rhs
@ -237,9 +241,11 @@ impl Inst {
| Inst::ConstantDoublePrecision | Inst::ConstantDoublePrecision
| Inst::Cmp(_) | Inst::Cmp(_)
| Inst::Branch(_) | Inst::Branch(_)
| Inst::Argument(_)
| Inst::Jump | Inst::Jump
| Inst::Return => None, | Inst::Return => None,
Inst::Phi2(ty) Inst::Phi2(ty)
| Inst::Call(ty)
| Inst::GetElementPtr(ty) | Inst::GetElementPtr(ty)
| Inst::Load(ty) | Inst::Load(ty)
| Inst::LoadRegister(ty) | Inst::LoadRegister(ty)
@ -281,6 +287,7 @@ impl Inst {
match self { match self {
Inst::Label Inst::Label
| Inst::Branch(_) | Inst::Branch(_)
| Inst::Argument(_)
| Inst::Jump | Inst::Jump
| Inst::ConstantBytes | Inst::ConstantBytes
| Inst::ConstantByte | Inst::ConstantByte
@ -325,6 +332,7 @@ impl Inst {
| Inst::IsGe(_) | Inst::IsGe(_)
| Inst::IsLe(_) | Inst::IsLe(_)
| Inst::Phi2(_) | Inst::Phi2(_)
| Inst::Call(_)
| Inst::ShiftLeft(_) | Inst::ShiftLeft(_)
| Inst::ShiftRightSigned(_) | Inst::ShiftRightSigned(_)
| Inst::ShiftRightUnsigned(_) => true, | Inst::ShiftRightUnsigned(_) => true,
@ -967,6 +975,33 @@ impl Mir {
pub fn gen_param(&mut self, ty: Type) -> u32 { pub fn gen_param(&mut self, ty: Type) -> u32 {
self.push(Inst::Parameter(ty), Data::none()) 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<Item = (Type, u32)>,
) -> 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::<Vec<_>>();
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 /// 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 { 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) => { Inst::Parameter(ty) => {
writeln!(w, "%{node} = param {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) => { Inst::Add(ty) => {
let (lhs, rhs) = data.as_binary(); let (lhs, rhs) = data.as_binary();
writeln!(w, "%{node} = add {ty} %{lhs}, {ty} %{rhs}") writeln!(w, "%{node} = add {ty} %{lhs}, {ty} %{rhs}")
@ -2005,6 +2051,13 @@ impl Mir {
let (src, _) = data.as_binary_noderefs(); let (src, _) = data.as_binary_noderefs();
references.insert((src, node)); 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 // these instructions have no inputs
// don't want a wildcard match here to make sure new instructions // don't want a wildcard match here to make sure new instructions
// are handled here when they are added. // are handled here when they are added.
@ -2020,6 +2073,7 @@ impl Mir {
| Inst::ConstantSinglePrecision | Inst::ConstantSinglePrecision
| Inst::ConstantDoublePrecision | Inst::ConstantDoublePrecision
| Inst::ExternRef(_) | Inst::ExternRef(_)
| Inst::Argument(_)
| Inst::Alloca => {} | Inst::Alloca => {}
} }
} }
@ -2060,6 +2114,7 @@ impl Mir {
Some(lhs) Some(lhs)
} }
Inst::Parameter(_) Inst::Parameter(_)
| Inst::Call(_)
| Inst::GetElementPtr(_) | Inst::GetElementPtr(_)
| Inst::LoadRegister(_) | Inst::LoadRegister(_)
| Inst::Load(_) | Inst::Load(_)
@ -2088,6 +2143,7 @@ impl Mir {
| Inst::Cmp(_) | Inst::Cmp(_)
| Inst::Branch(_) | Inst::Branch(_)
| Inst::Phi2(_) | Inst::Phi2(_)
| Inst::Argument(_)
| Inst::IsEq(_) | Inst::IsEq(_)
| Inst::IsNeq(_) | Inst::IsNeq(_)
| Inst::IsGt(_) | Inst::IsGt(_)
@ -2188,6 +2244,7 @@ impl core::fmt::Display for ImmRegMem {
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]
enum RipRelative { enum RipRelative {
Reference(String),
Label(Type, String), Label(Type, String),
#[allow(dead_code)] #[allow(dead_code)]
Offset(Type, i32), Offset(Type, i32),
@ -2196,6 +2253,7 @@ enum RipRelative {
impl RipRelative { impl RipRelative {
fn ty(&self) -> Type { fn ty(&self) -> Type {
match self { match self {
Self::Reference(_) => Type::QWord,
RipRelative::Label(ty, _) => *ty, RipRelative::Label(ty, _) => *ty,
RipRelative::Offset(ty, _) => *ty, RipRelative::Offset(ty, _) => *ty,
} }
@ -2205,6 +2263,7 @@ impl RipRelative {
impl core::fmt::Display for RipRelative { impl core::fmt::Display for RipRelative {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {
Self::Reference(label) => write!(f, "{label}"),
RipRelative::Label(ty, label) => write!(f, "{} ptr [rip + {label}]", ty.int_repr()), RipRelative::Label(ty, label) => write!(f, "{} ptr [rip + {label}]", ty.int_repr()),
RipRelative::Offset(ty, offset) => { RipRelative::Offset(ty, offset) => {
write!(f, "{} ptr [rip + {offset}]", ty.int_repr()) write!(f, "{} ptr [rip + {offset}]", ty.int_repr())
@ -2251,7 +2310,7 @@ impl Function {
let mut buf = String::new(); let mut buf = String::new();
let w = &mut buf; let w = &mut buf;
let name = strings.get_str(self.name).to_owned(); let name = strings.get_str(self.name).to_owned();
writeln!(w, ".{name}:")?; writeln!(w, "{name}:")?;
for (_, contents) in self.constants { for (_, contents) in self.constants {
writeln!(w, "{contents}")?; writeln!(w, "{contents}")?;
@ -2337,15 +2396,12 @@ impl Function {
writeln!(w, "push {reg}")?; writeln!(w, "push {reg}")?;
} }
let needs_frame = !saved_registers.is_empty() && self.stack_offset != 0; writeln!(w, "push rbp")?;
writeln!(w, "mov rbp, rsp")?;
if needs_frame { if self.stack_offset != 0 {
writeln!(w, "push rbp")?;
writeln!(w, "mov rbp, rsp")?;
writeln!(w, "sub rsp, {}", self.stack_offset)?; 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())?; write!(w, "{}", self.branches.remove(&NodeRef::MIN).unwrap())?;
for (branch, content) in &self.branches { for (branch, content) in &self.branches {
@ -2355,13 +2411,11 @@ impl Function {
writeln!(w, ".{name}__epilogue:")?; writeln!(w, ".{name}__epilogue:")?;
if needs_frame { writeln!(w, "mov rsp, rbp")?;
writeln!(w, "mov rsp, rbp")?; writeln!(w, "pop rbp")?;
writeln!(w, "pop rbp")?;
for reg in saved_registers.iter().rev() { for reg in saved_registers.iter().rev() {
writeln!(w, "pop {reg}")?; writeln!(w, "pop {reg}")?;
}
} }
writeln!(w, "ret")?; writeln!(w, "ret")?;
@ -2411,6 +2465,7 @@ impl Mir {
} }
Inst::GetElementPtr(ty) => liveness.get_register(node.into()).unwrap().into(), Inst::GetElementPtr(ty) => liveness.get_register(node.into()).unwrap().into(),
Inst::Parameter(ty) Inst::Parameter(ty)
| Inst::Call(ty)
| Inst::Phi2(ty) | Inst::Phi2(ty)
| Inst::Add(ty) | Inst::Add(ty)
| Inst::Sub(ty) | Inst::Sub(ty)
@ -2453,11 +2508,11 @@ impl Mir {
ImmRegMem::Mem(StackMem::new(offset, size)) ImmRegMem::Mem(StackMem::new(offset, size))
} }
Inst::ExternRef(ty) => { Inst::ExternRef(ty) => {
let ty = ty.unwrap_or(Type::QWord); // let ty = ty.unwrap_or(Type::QWord);
ImmRegMem::Rip(RipRelative::Label( ImmRegMem::Rip(RipRelative::Reference(format!(
ty, "{}",
format!(".{}", strings.get_str(data.as_index())), strings.get_str(data.as_index())
)) )))
} }
_ => { _ => {
unreachable!() 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::<Vec<_>>();
let mut sses = Register::SYSV_ARG_SSE.into_iter().rev().collect::<Vec<_>>();
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) => { Inst::Add(ty) => {
let dst = ty.register_width(liveness.get_register(node.into()).unwrap()); let dst = ty.register_width(liveness.get_register(node.into()).unwrap());
let (lhs, rhs) = data.as_binary(); let (lhs, rhs) = data.as_binary();

View file

@ -775,34 +775,34 @@ impl Tree {
} }
/// PREFIX_EXPR <- /// PREFIX_EXPR <-
/// PRIMARY_EXPR /// POSTFIX_EXPR
/// ! PRIMARY_EXPR /// ! POSTFIX_EXPR
/// - PRIMARY_EXPR /// - POSTFIX_EXPR
/// & PRIMARY_EXPR /// & POSTFIX_EXPR
/// * PRIMARY_EXPR /// * POSTFIX_EXPR
pub fn parse_prefix_expr(&mut self, tokens: &mut TokenIterator) -> Result<Node> { pub fn parse_prefix_expr(&mut self, tokens: &mut TokenIterator) -> Result<Node> {
match tokens.peek_token_or_err()?.token() { match tokens.peek_token_or_err()?.token() {
Token::Bang => { Token::Bang => {
_ = tokens.next(); _ = tokens.next();
let lhs = self.parse_primary_expr(tokens)?; let lhs = self.parse_postfix_expr(tokens)?;
Ok(self.nodes.push_tag(Tag::Not { lhs })) Ok(self.nodes.push_tag(Tag::Not { lhs }))
} }
Token::Minus => { Token::Minus => {
_ = tokens.next(); _ = tokens.next();
let lhs = self.parse_primary_expr(tokens)?; let lhs = self.parse_postfix_expr(tokens)?;
Ok(self.nodes.push_tag(Tag::Negate { lhs })) Ok(self.nodes.push_tag(Tag::Negate { lhs }))
} }
Token::Ampersand => { Token::Ampersand => {
_ = tokens.next(); _ = tokens.next();
let lhs = self.parse_primary_expr(tokens)?; let lhs = self.parse_postfix_expr(tokens)?;
Ok(self.nodes.push_tag(Tag::Ref { lhs })) Ok(self.nodes.push_tag(Tag::Ref { lhs }))
} }
Token::Star => { Token::Star => {
_ = tokens.next(); _ = tokens.next();
let lhs = self.parse_primary_expr(tokens)?; let lhs = self.parse_postfix_expr(tokens)?;
Ok(self.nodes.push_tag(Tag::Deref { lhs })) 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<Node> {
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<Node> {
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<Node> { pub fn parse_postfix_expr(&mut self, tokens: &mut TokenIterator) -> Result<Node> {
// TODO let lhs = self.parse_primary_expr(tokens)?;
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 <- /// PRIMARY_EXPR <-
@ -1121,7 +1181,9 @@ impl Tree {
vec![lhs] vec![lhs]
} }
} }
Tag::ArgumentList { parameters } => parameters.clone(), Tag::ArgumentList {
arguments: parameters,
} => parameters.clone(),
&Tag::Argument { name, expr } => { &Tag::Argument { name, expr } => {
if let Some(name) = name { if let Some(name) = name {
vec![name, expr] vec![name, expr]
@ -1323,9 +1385,36 @@ impl Tree {
writeln!(writer, ");")?; writeln!(writer, ");")?;
Ok(()) Ok(())
} }
Tag::CallExpr { .. } => todo!(), Tag::CallExpr { lhs, rhs } => {
Tag::ArgumentList { .. } => todo!(), self.render_node(writer, lhs, indent)?;
Tag::Argument { .. } => todo!(), 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 } => { Tag::ExplicitCast { lhs, typename } => {
self.render_node(writer, lhs, indent)?; self.render_node(writer, lhs, indent)?;
writeln_indented!( writeln_indented!(
@ -1788,7 +1877,7 @@ impl Tree {
ty 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::ExplicitCast { typename, .. } => self.type_of_node(*typename),
Tag::Deref { lhs } => self.type_of_node(*lhs).remove_ptr().unwrap(), Tag::Deref { lhs } => self.type_of_node(*lhs).remove_ptr().unwrap(),
Tag::Ref { lhs } => self.type_of_node(*lhs).into_ptr(), Tag::Ref { lhs } => self.type_of_node(*lhs).into_ptr(),
@ -2340,7 +2429,9 @@ impl Tree {
Tag::DeclRef(_) => todo!(), Tag::DeclRef(_) => todo!(),
Tag::GlobalRef(_) => todo!(), Tag::GlobalRef(_) => todo!(),
Tag::CallExpr { lhs, rhs } => todo!(), Tag::CallExpr { lhs, rhs } => todo!(),
Tag::ArgumentList { parameters } => todo!(), Tag::ArgumentList {
arguments: parameters,
} => todo!(),
Tag::Argument { name, expr } => todo!(), Tag::Argument { name, expr } => todo!(),
Tag::ExplicitCast { lhs, typename } => todo!(), Tag::ExplicitCast { lhs, typename } => todo!(),
Tag::Deref { lhs } => todo!(), Tag::Deref { lhs } => todo!(),

View file

@ -2,14 +2,14 @@
use std::{ use std::{
cmp::Ordering, cmp::Ordering,
collections::{BTreeMap, BTreeSet, HashMap}, collections::{BTreeMap, BTreeSet, HashMap, VecDeque},
}; };
use crate::{ use crate::{
ast::{IntegralType, Node as AstNode, Tag, Type}, ast::{IntegralType, Node as AstNode, Tag, Type},
parser::Tree, parser::Tree,
string_table::{ImmOrIndex, Index as StringsIndex, StringTable}, string_table::{ImmOrIndex, Index as StringsIndex, StringTable},
variant, writeln_indented, variant, write_indented, writeln_indented,
}; };
type Node = u32; type Node = u32;
@ -119,6 +119,7 @@ impl From<&Type> for Type2 {
crate::ast::FloatingType::Binary64 => Type2::Binary64, crate::ast::FloatingType::Binary64 => Type2::Binary64,
}, },
Type::Pointer { .. } => Type2::Pointer, Type::Pointer { .. } => Type2::Pointer,
Type::Fn { .. } => Type2::Pointer,
_ => { _ => {
unimplemented!("conversion from {value:?} to triples type not implemented") unimplemented!("conversion from {value:?} to triples type not implemented")
} }
@ -130,10 +131,18 @@ impl From<&Type> for Type2 {
pub enum Inst { pub enum Inst {
/// index /// index
Label, Label,
/// ast-node -> index
ExternRef(Type2),
/// index /// index
FunctionStart, FunctionStart,
/// None /// None
FunctionEnd, // marker FunctionEnd, // marker
/// lhs
Argument(Type2),
InlineType(Type2),
/// list of arguments
/// start, (inlinetype)end
Call(Node),
/// Value /// Value
/// lhs /// lhs
GlobalConstant(StringsIndex, Type2), GlobalConstant(StringsIndex, Type2),
@ -143,8 +152,6 @@ pub enum Inst {
ConstantU64, ConstantU64,
/// index /// index
ConstantMultiByte, ConstantMultiByte,
/// ast-node
ExternRef,
/// size, align /// size, align
Alloca, Alloca,
/// src /// src
@ -286,6 +293,7 @@ pub struct IRBuilder<'tree, 'ir> {
tree: &'tree mut Tree, tree: &'tree mut Tree,
type_map: HashMap<AstNode, Type>, type_map: HashMap<AstNode, Type>,
lookup: HashMap<AstNode, NodeOrList>, lookup: HashMap<AstNode, NodeOrList>,
fixup: Vec<Node>,
} }
impl core::ops::Index<Node> for IR { impl core::ops::Index<Node> for IR {
@ -303,6 +311,7 @@ impl<'tree, 'ir> IRBuilder<'tree, 'ir> {
tree, tree,
type_map: HashMap::new(), type_map: HashMap::new(),
lookup: HashMap::new(), lookup: HashMap::new(),
fixup: vec![],
} }
} }
@ -382,6 +391,40 @@ impl<'tree, 'ir> IRBuilder<'tree, 'ir> {
self.ir.push(Inst::FunctionEnd, None) 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::<Vec<_>>();
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 { Tag::Block {
statements, statements,
trailing_expr, trailing_expr,
@ -431,14 +474,11 @@ impl<'tree, 'ir> IRBuilder<'tree, 'ir> {
global global
} }
Tag::GlobalRef(decl) => { Tag::GlobalRef(decl) => {
let node = match self.lookup.get_mut(decl) { let ty = self.tree.type_of_node(*decl);
Some(NodeOrList::Node(decl)) => *decl, let node = self
lookup => { .ir
println!("lookup for ast decl %{}", decl.get()); .push(Inst::ExternRef(ty.into()), Some(Data::lhs(decl.get())));
println!("{lookup:?}"); self.fixup.push(node);
panic!("should not have any unresolved lookups")
}
};
node node
} }
Tag::DeclRef(decl) => match self.lookup.get_mut(decl) { Tag::DeclRef(decl) => match self.lookup.get_mut(decl) {
@ -680,6 +720,27 @@ impl IR {
for node in &global_decls { for node in &global_decls {
builder.visit(*node); 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 builder
} }
} }
@ -718,6 +779,25 @@ impl<'tree, 'ir> IRBuilder<'tree, 'ir> {
align 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 => { Inst::ConstantU32 => {
writeln_indented!(indent, w, "%{} = const i32 {}", node, data.as_u32())?; 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(); let (src, dst) = data.as_lhs_rhs();
writeln_indented!(indent, w, "%{} = store {ty}, ptr %{dst}, %{src}", node)?; writeln_indented!(indent, w, "%{} = store {ty}, ptr %{dst}, %{src}", node)?;
} }
Inst::ExternRef => { Inst::ExternRef(ty) => {
let ast = data.lhs; let idx = data.as_index();
writeln_indented!(indent, w, "%{} = extern reference ast-node %{}", node, ast)?; writeln_indented!(
indent,
w,
"%{node} = extern reference {ty} '{}'",
self.tree.strings.get_str(idx)
)?;
} }
Inst::Branch(condition) => { Inst::Branch(condition) => {
let (lhs, rhs) = data.as_lhs_rhs(); let (lhs, rhs) = data.as_lhs_rhs();
@ -1169,6 +1254,7 @@ impl<'a> IrToMirMapping<'a> {
match self.ir.nodes[ir as usize] { match self.ir.nodes[ir as usize] {
Inst::GlobalConstant(name, ty) => { Inst::GlobalConstant(name, ty) => {
eprintln!("does this even get hit anymore???????????????????//");
let ext = mir::NodeRef(mir.gen_extern(Some(ty.mir_type()), name)); let ext = mir::NodeRef(mir.gen_extern(Some(ty.mir_type()), name));
self.insert(ir, ext); self.insert(ir, ext);
Some(ext) Some(ext)
@ -1291,7 +1377,6 @@ impl<'a> MirBuilder<'a> {
} }
} }
} }
Inst::ExternRef => todo!(),
Inst::Alloca => { Inst::Alloca => {
let (l, r) = data.unwrap().as_lhs_rhs(); let (l, r) = data.unwrap().as_lhs_rhs();
mir.gen_alloca(l, r) mir.gen_alloca(l, r)
@ -1674,6 +1759,25 @@ impl<'a> MirBuilder<'a> {
br 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::<Vec<_>>();
mir.gen_call(ty.mir_type(), f, args)
}
Inst::Phi2(ty) => { Inst::Phi2(ty) => {
let (src, dst) = data.unwrap().as_lhs_rhs(); let (src, dst) = data.unwrap().as_lhs_rhs();
let lhs = mapping.get(&mut mir, src).unwrap().0; let lhs = mapping.get(&mut mir, src).unwrap().0;
@ -1686,6 +1790,12 @@ impl<'a> MirBuilder<'a> {
ext ext
} }
Inst::Argument(_) | Inst::InlineType(_) => {
continue;
}
Inst::ExternRef(ty) => {
mir.gen_extern(Some(ty.mir_type()), data.unwrap().as_index())
}
#[allow(unreachable_patterns)] #[allow(unreachable_patterns)]
_ => { _ => {
eprintln!("ir inst {inst:?} not supported in mir translation"); eprintln!("ir inst {inst:?} not supported in mir translation");

11
tests/legal/call.sea Normal file
View file

@ -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);
}

View file

@ -0,0 +1,5 @@
fn main() -> i32 {
return RANDOM;
}
const RANDOM: i32 = 4 + (1 << 3);