calling functions
This commit is contained in:
parent
4424ef875d
commit
568c3b2fa4
|
@ -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::*;
|
||||||
[
|
[
|
||||||
|
|
|
@ -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(_))
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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;
|
||||||
|
|
161
src/mir.rs
161
src/mir.rs
|
@ -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();
|
||||||
|
|
127
src/parser.rs
127
src/parser.rs
|
@ -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!(),
|
||||||
|
|
142
src/triples.rs
142
src/triples.rs
|
@ -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
11
tests/legal/call.sea
Normal 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);
|
||||||
|
}
|
5
tests/legal/global_var.sea
Normal file
5
tests/legal/global_var.sea
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
fn main() -> i32 {
|
||||||
|
return RANDOM;
|
||||||
|
}
|
||||||
|
|
||||||
|
const RANDOM: i32 = 4 + (1 << 3);
|
Loading…
Reference in a new issue