From 010e6d2bec926be7afc1b8d09a5c009792ac1c37 Mon Sep 17 00:00:00 2001 From: Janis Date: Sun, 25 Aug 2024 03:09:54 +0200 Subject: [PATCH] LANGUAGE CHANGES prefix binds tighter than as-expr, because &a as *u32 should be valid syntax i think it can actually do pointer arithmetic somewhat validly now? --- src/lexer.rs | 8 +- src/lib.rs | 3 +- src/mir.rs | 530 ++++++++++++++++++++++++++++++++ src/parser.rs | 74 +++-- src/string_table.rs | 1 + src/triples.rs | 716 ++++++++++++++++++++++++++++++++++++++++++-- 6 files changed, 1262 insertions(+), 70 deletions(-) create mode 100644 src/mir.rs diff --git a/src/lexer.rs b/src/lexer.rs index 7f78c18..b86f02c 100644 --- a/src/lexer.rs +++ b/src/lexer.rs @@ -985,19 +985,19 @@ fn parse_digit_part( allow_leading_underscore: bool, radix: Radix, ) -> Result<()> { - let radix = radix.is_digit(); + let is_digit = radix.is_digit(); if allow_leading_underscore { let _underscore = source.take_while_ref(|&c| c == '_').count(); } - let _need_digit = source.next_if(|&c| radix(c)).ok_or_else(|| { + let _need_digit = source.next_if(|&c| is_digit(c)).ok_or_else(|| { if source.peek() == Some('_') { Error::NumericalConstantDigitLeadingUnderscore } else { Error::NumericalConstantDigitNoDigit } })?; - let _rest = source.take_while_ref(|&c| radix(c) || c == '_').count(); + let _rest = source.take_while_ref(|&c| is_digit(c) || c == '_').count(); Ok(()) } @@ -1056,7 +1056,7 @@ fn parse_constant_inner(source: &mut Chars) -> Result { Err(e) => Err(e), }?; - if let Ok(_) = source.try_parse_result(|source| try_parse_integral_type(source)) { + if let Some(_) = source.try_parse_result(|source| try_parse_integral_type(source))? { return Ok(Token::IntegerConstant); } diff --git a/src/lib.rs b/src/lib.rs index 2af9238..fa145b0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,11 +7,12 @@ )] #![allow(unused_macros)] +pub mod asm; pub mod ast; -// pub mod codegen; pub mod common; pub mod error; pub mod lexer; +pub mod mir; pub mod parser; pub mod string_table; pub mod symbol_table; diff --git a/src/mir.rs b/src/mir.rs new file mode 100644 index 0000000..5b5bb37 --- /dev/null +++ b/src/mir.rs @@ -0,0 +1,530 @@ +//! Machine-level Intermediate Representation + +use crate::string_table::{Index as StringsIndex, StringTable}; + +#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] +pub enum Type { + /// 8bit integer + Byte, + /// 16bit integer + Word, + /// 32bit integer + DWord, + /// 64bit integer + QWord, + /// 32bit ieee-754 + SinglePrecision, + /// 64bit ieee-754 + DoublePrecision, + // XWord, + // YWord, + // ZWord, +} + +impl core::fmt::Display for Type { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let name = match self { + Type::Byte => "byte", + Type::Word => "word", + Type::DWord => "dword", + Type::QWord => "qword", + Type::SinglePrecision => "f32", + Type::DoublePrecision => "f64", + }; + + write!(f, "{name}") + } +} + +impl Type { + pub const fn is_floating(self) -> bool { + match self { + Type::SinglePrecision | Type::DoublePrecision => true, + _ => false, + } + } + pub const fn from_bitsize_int(size: u32) -> Type { + match size { + ..=8 => Self::Byte, + 9..=16 => Self::Word, + 17..=32 => Self::DWord, + 33..=64 => Self::QWord, + _ => unimplemented!(), + } + } + pub const fn from_bytesize_int(size: u32) -> Type { + Self::from_bitsize_int(size * 8) + } + + pub const fn bits(self) -> u32 { + match self { + Type::Byte => 8, + Type::Word => 16, + Type::DWord => 32, + Type::QWord => 64, + Type::SinglePrecision => 32, + Type::DoublePrecision => 64, + } + } + + pub const fn constant_inst(self) -> Inst { + match self { + Type::Byte => Inst::ConstantByte, + Type::Word => Inst::ConstantWord, + Type::SinglePrecision | Type::DWord => Inst::ConstantDWord, + Type::DoublePrecision | Type::QWord => Inst::ConstantQWord, + } + } + + pub const fn bytes(self) -> u32 { + match self { + Type::Byte => 1, + Type::Word => 2, + Type::DWord => 4, + Type::QWord => 8, + Type::SinglePrecision => 4, + Type::DoublePrecision => 8, + } + } +} + +#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] +pub enum Inst { + /// index + Label, + // Constant(Type), + /// index + ConstantBytes, + /// imm8 + ConstantByte, + /// imm16 + ConstantWord, + /// imm32 + ConstantDWord, + /// imm64 + ConstantQWord, + /// ast-node + ExternRef, + /// size, align + Alloca, + /// src + Load(Type), + /// src, dst + Store(Type), + /// src, idx, + GetElementPtr(Type), + Parameter(Type), + /// lhs, rhs + Add(Type), + /// lhs, rhs + Sub(Type), + /// lhs, rhs + Mul(Type), + /// lhs, rhs + MulSigned(Type), + /// lhs, rhs + Div(Type), + /// lhs, rhs + DivSigned(Type), + /// lhs, rhs + Rem(Type), + /// lhs, rhs + RemSigned(Type), + /// lhs, rhs + BitAnd(Type), + /// lhs, rhs + BitOr(Type), + /// lhs, rhs + BitXOr(Type), + /// lhs + Negate(Type), + /// lhs, rhs + ShiftLeft(Type), + /// lhs, rhs + ShiftRightSigned(Type), + /// lhs, rhs + ShiftRightUnsigned(Type), + /// lhs + ReturnValue, + Return, + //FunctionStart, +} + +#[derive(Clone, Copy)] +pub union Data { + none: (), + imm8: u8, + imm16: u16, + imm32: u32, + imm64: u64, + index: StringsIndex, + node: u32, + binary: (u32, u32), +} + +impl From for Data { + fn from(value: u8) -> Self { + Data::imm8(value) + } +} +impl From for Data { + fn from(value: u16) -> Self { + Data::imm16(value) + } +} +impl From for Data { + fn from(value: u32) -> Self { + Data::imm32(value) + } +} +impl From for Data { + fn from(value: u64) -> Self { + Data::imm64(value) + } +} + +impl Data { + pub fn imm8(v: u8) -> Data { + Self { imm8: v } + } + pub fn imm16(v: u16) -> Data { + Self { imm16: v } + } + pub fn imm32(v: u32) -> Data { + Self { imm32: v } + } + pub fn imm64(v: u64) -> Data { + Self { imm64: v } + } + pub fn index(v: StringsIndex) -> Data { + Self { index: v } + } + pub fn node(v: u32) -> Data { + Self { node: v } + } + pub fn binary(lhs: u32, rhs: u32) -> Data { + Self { binary: (lhs, rhs) } + } + pub fn none() -> Data { + Self { none: () } + } + + pub fn as_imm8(self) -> u8 { + unsafe { self.imm8 } + } + pub fn as_imm16(self) -> u16 { + unsafe { self.imm16 } + } + pub fn as_imm32(self) -> u32 { + unsafe { self.imm32 } + } + pub fn as_imm64(self) -> u64 { + unsafe { self.imm64 } + } + pub fn as_index(self) -> StringsIndex { + unsafe { self.index } + } + pub fn as_node(self) -> u32 { + unsafe { self.node } + } + pub fn as_binary(self) -> (u32, u32) { + unsafe { self.binary } + } +} + +pub struct Mir { + pub nodes: Vec, + pub data: Vec, +} + +impl Mir { + pub fn new() -> Mir { + Self { + nodes: Vec::new(), + data: Vec::new(), + } + } + + pub fn push(&mut self, inst: Inst, data: Data) -> u32 { + let node = self.nodes.len() as u32; + self.nodes.push(inst); + self.data.push(data); + + node + } + + pub fn gen_u8(&mut self, value: u8) -> u32 { + self.push(Inst::ConstantByte, Data::imm8(value)) + } + pub fn gen_u16(&mut self, value: u16) -> u32 { + self.push(Inst::ConstantWord, Data::imm16(value)) + } + pub fn gen_u32(&mut self, value: u32) -> u32 { + self.push(Inst::ConstantDWord, Data::imm32(value)) + } + pub fn gen_u64(&mut self, value: u64) -> u32 { + self.push(Inst::ConstantQWord, Data::imm64(value)) + } + + pub fn gen_label(&mut self, name: StringsIndex) -> u32 { + self.push(Inst::Label, Data::index(name)) + } + pub fn gen_alloca(&mut self, size: u32, align: u32) -> u32 { + self.push(Inst::Alloca, Data::binary(size, align)) + } + pub fn gen_load(&mut self, ty: Type, src: u32) -> u32 { + self.push(Inst::Load(ty), Data::node(src)) + } + pub fn gen_get_element_ptr(&mut self, ty: Type, src: u32, index: u32) -> u32 { + self.push(Inst::GetElementPtr(ty), Data::binary(src, index)) + } + pub fn gen_store(&mut self, ty: Type, src: u32, dst: u32) -> u32 { + self.push(Inst::Store(ty), Data::binary(src, dst)) + } + pub fn gen_param(&mut self, ty: Type) -> u32 { + self.push(Inst::Parameter(ty), Data::none()) + } + + pub fn gen_truncate(&mut self, src: u32, ty: Type, signed: bool, bits: u16) -> u32 { + // example: u4 + // ty = byte + // 1111_1111 << 4 = 1111_0000 + // mask = 0000_1111; + // shift = 8 - 4; + let shift = ty.bits() as u8 - bits as u8; + let mask = !(!0u64 << bits); + + let mask = match ty { + Type::Byte => self.gen_u8(mask as u8), + Type::Word => self.gen_u16(mask as u16), + Type::SinglePrecision | Type::DWord => self.gen_u32(mask as u32), + Type::DoublePrecision | Type::QWord => self.gen_u64(mask as u64), + }; + + let masked = self.gen_bitand(ty, src, mask); + + if signed { + let shift = self.gen_u8(shift); + let tmp = self.gen_shl(ty, masked, shift); + let tmp = self.gen_sar(ty, tmp, shift); + tmp + } else { + masked + } + } + + pub fn gen_add(&mut self, ty: Type, lhs: u32, rhs: u32) -> u32 { + self.push(Inst::Add(ty), Data::binary(lhs, rhs)) + } + pub fn gen_sub(&mut self, ty: Type, lhs: u32, rhs: u32) -> u32 { + self.push(Inst::Sub(ty), Data::binary(lhs, rhs)) + } + pub fn gen_mul(&mut self, ty: Type, signed: bool, lhs: u32, rhs: u32) -> u32 { + if signed && !ty.is_floating() { + self.gen_mul_signed(ty, lhs, rhs) + } else { + self.gen_mul_unsigned(ty, lhs, rhs) + } + } + pub fn gen_mul_unsigned(&mut self, ty: Type, lhs: u32, rhs: u32) -> u32 { + self.push(Inst::Mul(ty), Data::binary(lhs, rhs)) + } + pub fn gen_mul_signed(&mut self, ty: Type, lhs: u32, rhs: u32) -> u32 { + self.push(Inst::MulSigned(ty), Data::binary(lhs, rhs)) + } + pub fn gen_div(&mut self, ty: Type, signed: bool, lhs: u32, rhs: u32) -> u32 { + if signed && !ty.is_floating() { + self.gen_div_signed(ty, lhs, rhs) + } else { + self.gen_div_unsigned(ty, lhs, rhs) + } + } + pub fn gen_div_unsigned(&mut self, ty: Type, lhs: u32, rhs: u32) -> u32 { + self.push(Inst::Div(ty), Data::binary(lhs, rhs)) + } + pub fn gen_div_signed(&mut self, ty: Type, lhs: u32, rhs: u32) -> u32 { + self.push(Inst::DivSigned(ty), Data::binary(lhs, rhs)) + } + pub fn gen_rem(&mut self, ty: Type, signed: bool, lhs: u32, rhs: u32) -> u32 { + if signed && !ty.is_floating() { + self.gen_rem_signed(ty, lhs, rhs) + } else { + self.gen_rem_unsigned(ty, lhs, rhs) + } + } + pub fn gen_rem_unsigned(&mut self, ty: Type, lhs: u32, rhs: u32) -> u32 { + self.push(Inst::Rem(ty), Data::binary(lhs, rhs)) + } + pub fn gen_rem_signed(&mut self, ty: Type, lhs: u32, rhs: u32) -> u32 { + self.push(Inst::RemSigned(ty), Data::binary(lhs, rhs)) + } + + pub fn gen_bitand(&mut self, ty: Type, lhs: u32, rhs: u32) -> u32 { + self.push(Inst::BitAnd(ty), Data::binary(lhs, rhs)) + } + pub fn gen_bitor(&mut self, ty: Type, lhs: u32, rhs: u32) -> u32 { + self.push(Inst::BitAnd(ty), Data::binary(lhs, rhs)) + } + pub fn gen_bitxor(&mut self, ty: Type, lhs: u32, rhs: u32) -> u32 { + self.push(Inst::BitAnd(ty), Data::binary(lhs, rhs)) + } + pub fn gen_negate(&mut self, ty: Type, src: u32) -> u32 { + self.push(Inst::Negate(ty), Data::node(src)) + } + + #[doc(alias = "gen_shift_left")] + pub fn gen_shl(&mut self, ty: Type, src: u32, shift: u32) -> u32 { + self.push(Inst::ShiftLeft(ty), Data::binary(src, shift)) + } + #[doc(alias = "gen_shift_right")] + pub fn gen_shr(&mut self, ty: Type, src: u32, shift: u32) -> u32 { + self.push(Inst::ShiftRightUnsigned(ty), Data::binary(src, shift)) + } + #[doc(alias = "gen_shift_right_signed")] + pub fn gen_sar(&mut self, ty: Type, src: u32, shift: u32) -> u32 { + self.push(Inst::ShiftRightSigned(ty), Data::binary(src, shift)) + } + pub fn gen_ret_val(&mut self, val: u32) -> u32 { + self.push(Inst::ReturnValue, Data::node(val)) + } + pub fn gen_ret(&mut self) -> u32 { + self.push(Inst::Return, Data::none()) + } +} + +impl Mir { + fn render_node( + &self, + w: &mut W, + strings: &StringTable, + node: u32, + ) -> core::fmt::Result { + let idx = node as usize; + let inst = self.nodes[idx]; + let data = self.data[idx]; + match inst { + Inst::Label => writeln!(w, "%{node} = {}", strings.get_str(data.as_index())), + Inst::ConstantBytes => writeln!( + w, + "%{node} = bytes({:x?})", + strings.get_bytes(data.as_index()) + ), + Inst::ConstantByte => writeln!(w, "%{node} = imm8({:x?})", data.as_imm8()), + Inst::ConstantWord => writeln!(w, "%{node} = imm16({:x?})", data.as_imm16()), + Inst::ConstantDWord => writeln!(w, "%{node} = imm32({:x?})", data.as_imm32()), + Inst::ConstantQWord => writeln!(w, "%{node} = imm64({:x?})", data.as_imm64()), + Inst::ExternRef => writeln!(w, "%{node} = extern %%{}", data.as_node()), + Inst::Alloca => { + let (size, align) = data.as_binary(); + writeln!(w, "%{node} = alloca {size}, {align}") + } + Inst::GetElementPtr(ty) => { + let (ptr, idx) = data.as_binary(); + writeln!(w, "%{node} = get element ptr {ty}, ptr %{ptr}, idx {idx}") + } + Inst::Load(ty) => { + writeln!(w, "%{node} = load {ty}, ptr %{}", data.as_node()) + } + Inst::Store(ty) => { + let (src, dst) = data.as_binary(); + writeln!(w, "%{node} = store {ty}, ptr %{dst}, {ty} %{src}") + } + Inst::Parameter(ty) => { + writeln!(w, "%{node} = param {ty}") + } + Inst::Add(ty) => { + let (lhs, rhs) = data.as_binary(); + writeln!(w, "%{node} = add {ty} %{lhs}, {ty} %{rhs}") + } + Inst::Sub(ty) => { + let (lhs, rhs) = data.as_binary(); + writeln!(w, "%{node} = sub {ty} %{lhs}, {ty} %{rhs}") + } + Inst::Mul(ty) => { + let (lhs, rhs) = data.as_binary(); + writeln!(w, "%{node} = mul {ty} %{lhs}, {ty} %{rhs}") + } + Inst::MulSigned(ty) => { + let (lhs, rhs) = data.as_binary(); + writeln!(w, "%{node} = signed mul {ty} %{lhs}, {ty} %{rhs}") + } + Inst::Div(ty) => { + let (lhs, rhs) = data.as_binary(); + writeln!(w, "%{node} = div {ty} %{lhs}, {ty} %{rhs}") + } + Inst::DivSigned(ty) => { + let (lhs, rhs) = data.as_binary(); + writeln!(w, "%{node} = signed div {ty} %{lhs}, {ty} %{rhs}") + } + Inst::Rem(ty) => { + let (lhs, rhs) = data.as_binary(); + writeln!(w, "%{node} = rem {ty} %{lhs}, {ty} %{rhs}") + } + Inst::RemSigned(ty) => { + let (lhs, rhs) = data.as_binary(); + writeln!(w, "%{node} = signed rem {ty} %{lhs}, {ty} %{rhs}") + } + Inst::BitAnd(ty) => { + let (lhs, rhs) = data.as_binary(); + writeln!(w, "%{node} = bitand {ty} %{lhs}, {ty} %{rhs}") + } + Inst::BitOr(ty) => { + let (lhs, rhs) = data.as_binary(); + writeln!(w, "%{node} = bitor {ty} %{lhs}, {ty} %{rhs}") + } + Inst::BitXOr(ty) => { + let (lhs, rhs) = data.as_binary(); + writeln!(w, "%{node} = bitxor {ty} %{lhs}, {ty} %{rhs}") + } + Inst::Negate(ty) => { + let lhs = data.as_node(); + writeln!(w, "%{node} = negate {ty} %{lhs}") + } + Inst::ShiftLeft(ty) => { + let (lhs, rhs) = data.as_binary(); + writeln!(w, "%{node} = shift left {ty} %{lhs}, {ty} %{rhs}") + } + Inst::ShiftRightUnsigned(ty) => { + let (lhs, rhs) = data.as_binary(); + writeln!(w, "%{node} = shift right {ty} %{lhs}, {ty} %{rhs}") + } + Inst::ShiftRightSigned(ty) => { + let (lhs, rhs) = data.as_binary(); + writeln!(w, "%{node} = signed shift right {ty} %{lhs}, {ty} %{rhs}") + } + Inst::ReturnValue => { + let lhs = data.as_node(); + writeln!(w, "%{node} = return %{lhs}") + } + Inst::Return => { + writeln!(w, "%{node} = return") + } + } + } + + pub fn render( + &self, + w: &mut W, + strings: &StringTable, + ) -> core::fmt::Result { + for node in 0..self.nodes.len() { + self.render_node(w, strings, node as u32)?; + } + Ok(()) + } + + pub fn display<'a, 'b>(&'a self, strings: &'b StringTable) -> DisplayMir<'a, 'b> { + DisplayMir { mir: self, strings } + } +} + +pub struct DisplayMir<'a, 'b> { + mir: &'a Mir, + strings: &'b StringTable, +} + +impl<'a, 'b> core::fmt::Display for DisplayMir<'a, 'b> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.mir.render(f, &self.strings) + } +} diff --git a/src/parser.rs b/src/parser.rs index 7833eaf..ce9cd04 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -237,6 +237,14 @@ impl Tree { // TODO: figure out how to do this safely for bigger types, whether to // wrap, saturate, or else. let iter = &mut lexeme.char_indices(); + + match radix { + Radix::Bin | Radix::Oct | Radix::Hex => { + _ = iter.advance_by(2); + } + _ => {} + } + let digits = iter .take_while_ref(|&(_, c)| radix.is_digit()(c) || c == '_') .filter(|&(_, c)| c != '_') @@ -694,31 +702,31 @@ impl Tree { } /// BINARY_EXPR <- - /// PREFIX_EXPR - /// PREFIX_EXPR * EXPRESSION - /// PREFIX_EXPR / EXPRESSION - /// PREFIX_EXPR % EXPRESSION - /// PREFIX_EXPR + EXPRESSION - /// PREFIX_EXPR - EXPRESSION - /// PREFIX_EXPR << EXPRESSION - /// PREFIX_EXPR >> EXPRESSION - /// PREFIX_EXPR < EXPRESSION - /// PREFIX_EXPR > EXPRESSION - /// PREFIX_EXPR <= EXPRESSION - /// PREFIX_EXPR >= EXPRESSION - /// PREFIX_EXPR == EXPRESSION - /// PREFIX_EXPR != EXPRESSION - /// PREFIX_EXPR & EXPRESSION - /// PREFIX_EXPR ^ EXPRESSION - /// PREFIX_EXPR | EXPRESSION - /// PREFIX_EXPR && EXPRESSION - /// PREFIX_EXPR || EXPRESSION + /// AS_EXPR + /// AS_EXPR * EXPRESSION + /// AS_EXPR / EXPRESSION + /// AS_EXPR % EXPRESSION + /// AS_EXPR + EXPRESSION + /// AS_EXPR - EXPRESSION + /// AS_EXPR << EXPRESSION + /// AS_EXPR >> EXPRESSION + /// AS_EXPR < EXPRESSION + /// AS_EXPR > EXPRESSION + /// AS_EXPR <= EXPRESSION + /// AS_EXPR >= EXPRESSION + /// AS_EXPR == EXPRESSION + /// AS_EXPR != EXPRESSION + /// AS_EXPR & EXPRESSION + /// AS_EXPR ^ EXPRESSION + /// AS_EXPR | EXPRESSION + /// AS_EXPR && EXPRESSION + /// AS_EXPR || EXPRESSION pub fn parse_binary_expr( &mut self, tokens: &mut TokenIterator, precedence: u32, ) -> Result { - let mut node = self.parse_prefix_expr(tokens)?; + let mut node = self.parse_as_expr(tokens)?; loop { let Some(tok) = tokens.peek_token() else { @@ -766,42 +774,42 @@ impl Tree { } /// PREFIX_EXPR <- - /// AS_EXPR - /// ! AS_EXPR - /// - AS_EXPR - /// & AS_EXPR - /// * AS_EXPR + /// PRIMARY_EXPR + /// ! PRIMARY_EXPR + /// - PRIMARY_EXPR + /// & PRIMARY_EXPR + /// * PRIMARY_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_as_expr(tokens)?; + let lhs = self.parse_primary_expr(tokens)?; Ok(self.nodes.push_tag(Tag::Not { lhs })) } Token::Minus => { _ = tokens.next(); - let lhs = self.parse_as_expr(tokens)?; + let lhs = self.parse_primary_expr(tokens)?; Ok(self.nodes.push_tag(Tag::Negate { lhs })) } Token::Ampersand => { _ = tokens.next(); - let lhs = self.parse_as_expr(tokens)?; + let lhs = self.parse_primary_expr(tokens)?; Ok(self.nodes.push_tag(Tag::Ref { lhs })) } Token::Star => { _ = tokens.next(); - let lhs = self.parse_as_expr(tokens)?; + let lhs = self.parse_primary_expr(tokens)?; Ok(self.nodes.push_tag(Tag::Deref { lhs })) } - _ => self.parse_as_expr(tokens), + _ => self.parse_primary_expr(tokens), } } /// AS_EXPR <- - /// PRIMARY_EXPR - /// PRIMARY_EXPR as TYPENAME + /// PREFIX_EXPR + /// PREFIX_EXPR as TYPENAME pub fn parse_as_expr(&mut self, tokens: &mut TokenIterator) -> Result { - let expr = self.parse_primary_expr(tokens)?; + let expr = self.parse_prefix_expr(tokens)?; if tokens.eat_token(Token::As).is_some() { let typename = self.parse_typename(tokens)?; diff --git a/src/string_table.rs b/src/string_table.rs index b98e58b..ee91107 100644 --- a/src/string_table.rs +++ b/src/string_table.rs @@ -19,6 +19,7 @@ impl Index { } } +#[derive(Clone)] pub struct StringTable { bytes: Vec, indices: BTreeMap, diff --git a/src/triples.rs b/src/triples.rs index 6e3b352..cd21da7 100644 --- a/src/triples.rs +++ b/src/triples.rs @@ -19,7 +19,7 @@ enum NodeOrList { #[derive(Debug, PartialEq, Eq, Clone, Copy)] enum Type2 { - Integral(u16), + Integral(bool, u16), Binary32, Binary64, Bool, @@ -29,7 +29,7 @@ enum Type2 { impl Type2 { fn size(&self) -> u32 { match self { - Type2::Integral(bits) => bits.div_ceil(8) as u32, + Type2::Integral(_signed, bits) => bits.div_ceil(8) as u32, Type2::Binary32 => 4, Type2::Binary64 => 8, Type2::Bool => 1, @@ -45,7 +45,7 @@ impl Type2 { impl core::fmt::Display for Type2 { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - Type2::Integral(bits) => write!(f, "i{bits}"), + Type2::Integral(signed, bits) => write!(f, "{}{bits}", if *signed { "i" } else { "u" }), Type2::Binary32 => write!(f, "f32"), Type2::Binary64 => write!(f, "f64"), Type2::Bool => write!(f, "bool"), @@ -64,13 +64,15 @@ impl From<&Type> for Type2 { fn from(value: &Type) -> Self { match value { Type::Bool => Type2::Bool, - Type::Integer(i) => Type2::Integral(i.bits), + Type::Integer(i) => Type2::Integral(i.signed, i.bits), Type::Floating(f) => match f { crate::ast::FloatingType::Binary32 => Type2::Binary32, crate::ast::FloatingType::Binary64 => Type2::Binary64, }, Type::Pointer { .. } => Type2::Pointer, - _ => todo!(), + _ => { + unimplemented!("conversion from {value:?} to triples type not implemented") + } } } } @@ -115,6 +117,10 @@ enum Inst { BitOr(Type2), /// lhs, rhs BitXOr(Type2), + /// lhs, rhs + ShiftLeft(Type2), + /// lhs, rhs + ShiftRight(Type2), /// lhs Negate(Type2), /// lhs @@ -314,6 +320,13 @@ impl<'tree, 'ir> IRBuilder<'tree, 'ir> { self.ir .push(Inst::Add(ty.into()), Some(Data::new(lhs, rhs))) } + Tag::Sub { lhs, rhs } => { + let ty = self.tree.type_of_node(*lhs); + let lhs = self.visit(*lhs); + let rhs = self.visit(*rhs); + self.ir + .push(Inst::Sub(ty.into()), Some(Data::new(lhs, rhs))) + } Tag::Mul { lhs, rhs } => { let ty = self.tree.type_of_node(*lhs); let lhs = self.visit(*lhs); @@ -326,6 +339,20 @@ impl<'tree, 'ir> IRBuilder<'tree, 'ir> { let lhs = self.visit(*lhs); self.ir.push(Inst::Negate(ty.into()), Some(Data::lhs(lhs))) } + Tag::Shl { lhs, rhs } => { + let ty = self.tree.type_of_node(*lhs); + let lhs = self.visit(*lhs); + let rhs = self.visit(*rhs); + self.ir + .push(Inst::ShiftLeft(ty.into()), Some(Data::new(lhs, rhs))) + } + Tag::Shr { lhs, rhs } => { + let ty = self.tree.type_of_node(*lhs); + let lhs = self.visit(*lhs); + let rhs = self.visit(*rhs); + self.ir + .push(Inst::ShiftRight(ty.into()), Some(Data::new(lhs, rhs))) + } Tag::DeclRef(decl) => match self.lookup.get_mut(decl) { Some(NodeOrList::Node(decl)) => *decl, lookup => { @@ -338,7 +365,10 @@ impl<'tree, 'ir> IRBuilder<'tree, 'ir> { Tag::Ref { lhs } => { let ty = self.tree.type_of_node(*lhs); let lhs = self.visit(*lhs); - self.ir.push(Inst::Load(ty.into()), Some(Data::lhs(lhs))) + // self.ir.push(Inst::Load(ty.into()), Some(Data::lhs(lhs))) + // nothing happens here because lhs is of type pointer + self.ir + .push(Inst::GetElementPtr(ty.into()), Some(Data::new(lhs, 0))) } Tag::Constant { bytes, .. } => match bytes { ImmOrIndex::U64(v) => self.ir.push(Inst::ConstantU64, Some((*v).into())), @@ -347,6 +377,26 @@ impl<'tree, 'ir> IRBuilder<'tree, 'ir> { self.ir.push(Inst::ConstantMultiByte, Some((*idx).into())) } }, + Tag::ExplicitCast { lhs, typename } => { + let l_ty = self.tree.type_of_node(*lhs).clone(); + let r_ty = self.tree.type_of_node(*typename).clone(); + + let lhs = self.visit(*lhs); + + if l_ty.bit_width() == r_ty.bit_width() { + //noop? + lhs + } else { + let alloc = self.ir.push( + Inst::Alloca, + Some(Data::new(r_ty.size_of(), r_ty.align_of())), + ); + let load = self + .ir + .push(Inst::Load(l_ty.into()), Some(Data::lhs(alloc))); + load + } + } _ => { dbg!(&self.tree.nodes[node]); todo!() @@ -396,7 +446,8 @@ impl<'tree, 'ir> IRBuilder<'tree, 'ir> { let data = self.ir.data[node as usize] .clone() .unwrap_or(Data::new(0, 0)); - match &self.ir.nodes[node as usize] { + let inst = self.ir.nodes[node as usize]; + match inst { Inst::Label => { let label = self.tree.strings.get_str(data.as_index()); writeln_indented!(indent - 1, w, "%{} = {label}:", node)?; @@ -432,15 +483,35 @@ impl<'tree, 'ir> IRBuilder<'tree, 'ir> { } Inst::Sub(ty) => { let (lhs, rhs) = data.as_lhs_rhs(); - writeln_indented!(indent, w, "%{} = sub_{ty}(%{} + %{})", node, lhs, rhs)?; + writeln_indented!(indent, w, "%{} = sub_{ty}(%{} - %{})", node, lhs, rhs)?; } Inst::Mul(ty) => { let (lhs, rhs) = data.as_lhs_rhs(); - writeln_indented!(indent, w, "%{} = mul_{ty}(%{} + %{})", node, lhs, rhs)?; + writeln_indented!(indent, w, "%{} = mul_{ty}(%{} * %{})", node, lhs, rhs)?; } Inst::Negate(ty) => { writeln_indented!(indent, w, "%{} = negate_{ty}(%{})", node, data.lhs)?; } + Inst::ShiftLeft(ty) => { + writeln_indented!( + indent, + w, + "%{} = shl_{ty}(%{} << %{})", + node, + data.lhs, + data.rhs + )?; + } + Inst::ShiftRight(ty) => { + writeln_indented!( + indent, + w, + "%{} = shr_{ty}(%{} >> %{})", + node, + data.lhs, + data.rhs + )?; + } Inst::ReturnValue => { writeln_indented!(indent, w, "%{} = return %{}", node, data.lhs)?; } @@ -474,7 +545,7 @@ impl<'tree, 'ir> IRBuilder<'tree, 'ir> { writeln_indented!(indent, w, "%{} = extern reference ast-node %{}", node, ast)?; } _ => { - unimplemented!() + unimplemented!("{inst:?} rendering unimplemented") } } Ok(()) @@ -518,8 +589,8 @@ enum Width { impl Width { fn from_size(size: u32) -> Option { match size { - 0..=1 => Some(Self::Byte), - 1..=2 => Some(Self::Word), + 1 => Some(Self::Byte), + 2 => Some(Self::Word), 3..=4 => Some(Self::DWord), 5..=8 => Some(Self::QWord), _ => None, @@ -881,12 +952,34 @@ impl<'a> Assembler<'a> { "src_reg from node %{src} not found: {registers:?}" )); let dst_reg = register_store.take_any().unwrap(); - writeln!( - func.branches.get_mut(¤t_branch).unwrap(), - "mov {}, {}", - src, - dst_reg.display(Width::from_size(ty.size()).unwrap()), - )?; + + match src { + ImmRegMem::Reg(_, _) => { + writeln!( + func.branches.get_mut(¤t_branch).unwrap(), + "mov ({}), {}", + src, + dst_reg.display(Width::from_size(ty.size()).unwrap()), + )?; + } + _ => { + let tmp_reg = register_store.take_any().unwrap(); + writeln!( + func.branches.get_mut(¤t_branch).unwrap(), + "mov {}, {}", + src, + tmp_reg.display(Width::QWord), + )?; + writeln!( + func.branches.get_mut(¤t_branch).unwrap(), + "mov ({}), {}", + tmp_reg.display(Width::QWord), + dst_reg.display(Width::from_size(ty.size()).unwrap()), + )?; + register_store.free(tmp_reg); + } + } + if let ImmRegMem::Reg(reg, _) = src { register_store.free(reg); registers.remove(®); @@ -931,7 +1024,47 @@ impl<'a> Assembler<'a> { registers.remove(®); } } - Inst::GetElementPtr(_) => todo!(), + Inst::GetElementPtr(ty) => { + let (ptr, idx) = data.unwrap().as_lhs_rhs(); + let src = registers + .iter() + .find(|(_, node)| node == &&ptr) + .map(|(reg, _)| ImmRegMem::Reg(*reg, Width::from_size(ty.size()).unwrap())) + .or_else(|| { + allocas + .get(&ptr) + .map(|&offset| ImmRegMem::Mem(StackMem::new(offset))) + }) + .expect(&format!( + "src_reg from node %{ptr} not found: {registers:?}" + )); + let dst_reg = register_store.take_any().unwrap(); + + if let ImmRegMem::Mem(_) = &src { + writeln!( + func.branches.get_mut(¤t_branch).unwrap(), + "lea {}, {}", + src, + ImmRegMem::Reg(dst_reg, Width::QWord), + )?; + } + + let offset = idx * ty.size(); + if offset != 0 { + writeln!( + func.branches.get_mut(¤t_branch).unwrap(), + "lea {}({}), {}", + offset, + ImmRegMem::Reg(dst_reg, Width::QWord), + ImmRegMem::Reg(dst_reg, Width::QWord), + )?; + } + if let ImmRegMem::Reg(reg, _) = src { + register_store.free(reg); + registers.remove(®); + } + registers.insert(dst_reg, node); + } Inst::Parameter => { let param_reg = Registers::sysv_param_idx(param_count).unwrap(); param_count += 1; @@ -960,38 +1093,66 @@ impl<'a> Assembler<'a> { } Inst::Sub(ty) => { let (src, dst) = data.unwrap().as_lhs_rhs(); - let (&src_reg, _) = registers.iter().find(|(_, node)| node == &&src).unwrap(); + let src = registers + .iter() + .find(|(_, node)| node == &&src) + .map(|(reg, _)| ImmRegMem::Reg(*reg, Width::from_size(ty.size()).unwrap())) + .or_else(|| { + allocas + .get(&src) + .map(|&offset| ImmRegMem::Mem(StackMem::new(offset))) + }) + .expect(&format!( + "src_reg from node %{src} not found: {registers:?}" + )); let (&dst_reg, _) = registers.iter().find(|(_, node)| node == &&dst).unwrap(); writeln!( func.branches.get_mut(¤t_branch).unwrap(), "sub {}, {}", - src_reg.display(Width::from_size(ty.size()).unwrap()), + src, dst_reg.display(Width::from_size(ty.size()).unwrap()), )?; - if src_reg != dst_reg { - register_store.free(src_reg); - registers.remove(&src_reg); + if let ImmRegMem::Reg(reg, _) = src { + if reg != dst_reg { + register_store.free(reg); + registers.remove(®); + } } registers.insert(dst_reg, node); } Inst::Mul(ty) => { let (src, dst) = data.unwrap().as_lhs_rhs(); - let (&src_reg, _) = registers.iter().find(|(_, node)| node == &&src).unwrap(); + let src = registers + .iter() + .find(|(_, node)| node == &&src) + .map(|(reg, _)| ImmRegMem::Reg(*reg, Width::from_size(ty.size()).unwrap())) + .or_else(|| { + allocas + .get(&src) + .map(|&offset| ImmRegMem::Mem(StackMem::new(offset))) + }) + .expect(&format!( + "src_reg from node %{src} not found: {registers:?}" + )); let (&dst_reg, _) = registers.iter().find(|(_, node)| node == &&dst).unwrap(); writeln!( func.branches.get_mut(¤t_branch).unwrap(), "imul {}, {}", - src_reg.display(Width::from_size(ty.size()).unwrap()), + src, dst_reg.display(Width::from_size(ty.size()).unwrap()), )?; - if src_reg != dst_reg { - register_store.free(src_reg); - registers.remove(&src_reg); + if let ImmRegMem::Reg(reg, _) = src { + if reg != dst_reg { + register_store.free(reg); + registers.remove(®); + } } registers.insert(dst_reg, node); } + Inst::ShiftLeft(_) => todo!(), + Inst::ShiftRight(_) => todo!(), Inst::Div(_) => todo!(), Inst::Rem(_) => todo!(), Inst::BitAnd(_) => todo!(), @@ -1059,19 +1220,506 @@ impl<'a> Assembler<'a> { } } +use crate::mir; + +struct MirBuilder<'a> { + ir: IRIter<'a>, + strings: StringTable, + mir: mir::Mir, +} + +impl<'a> MirBuilder<'a> { + fn new(ir: &'a IR, strings: StringTable) -> MirBuilder<'a> { + Self { + ir: IRIter { + ir, + offset: 0, + item: None, + }, + strings, + mir: mir::Mir::new(), + } + } + + fn build_function(&mut self, name: StringsIndex) { + let mut mir = mir::Mir::new(); + let mut mapping = BTreeMap::::new(); + + loop { + let ir_node = self.ir.node(); + let Some((inst, data)) = self.ir.next() else { + break; + }; + let node = match inst { + Inst::FunctionStart => { + self.ir.offset -= 1; + break; + } + Inst::Label => { + mir.push(mir::Inst::Label, mir::Data::index(data.unwrap().as_index())) + } + Inst::ConstantU32 => mir.push( + mir::Inst::ConstantDWord, + mir::Data::imm32(data.unwrap().as_u32()), + ), + Inst::ConstantU64 => mir.push( + mir::Inst::ConstantQWord, + mir::Data::imm64(data.unwrap().as_u64()), + ), + Inst::ConstantMultiByte => { + let bytes = self.strings.get_bytes(data.unwrap().as_index()); + let mut buf = [0u8; 8]; + match bytes.len() { + 1 => mir.gen_u8(bytes[0]), + 2 => mir.gen_u16(u16::from_le_bytes(bytes[..2].try_into().unwrap())), + 3..=4 => { + buf[..bytes.len()].copy_from_slice(bytes); + mir.gen_u32(u32::from_le_bytes(buf[..4].try_into().unwrap())) + } + 5..=8 => { + buf[..bytes.len()].copy_from_slice(bytes); + mir.gen_u64(u64::from_le_bytes(buf[..8].try_into().unwrap())) + } + _ => { + unimplemented!( + "constants larger than 8 bytes are not currently supported!" + ) + } + } + } + Inst::ExternRef => todo!(), + Inst::Alloca => { + let (l, r) = data.unwrap().as_lhs_rhs(); + mir.gen_alloca(l, r) + } + Inst::Load(ty) => { + let ty = mir::Type::from_bytesize_int(ty.size()); + let src = *mapping.get(&data.unwrap().as_u32()).unwrap(); + mir.gen_load(ty, src) + } + Inst::Store(ty) => { + let ty = mir::Type::from_bytesize_int(ty.size()); + let (src, dst) = data.unwrap().as_lhs_rhs(); + let src = *mapping.get(&src).unwrap(); + let dst = *mapping.get(&dst).unwrap(); + mir.gen_store(ty, src, dst) + } + Inst::GetElementPtr(ty) => { + let ty = mir::Type::from_bytesize_int(ty.size()); + let (ptr, idx) = data.unwrap().as_lhs_rhs(); + let src = *mapping.get(&ptr).unwrap(); + mir.gen_get_element_ptr(ty, src, idx) + } + Inst::Parameter => { + let (size, _) = data.unwrap().as_lhs_rhs(); + let ty = mir::Type::from_bytesize_int(size); + mir.gen_param(ty) + } + Inst::Add(ty) => { + let (src, dst) = data.unwrap().as_lhs_rhs(); + let lhs = *mapping.get(&src).unwrap(); + let rhs = *mapping.get(&dst).unwrap(); + + match ty { + Type2::Integral(signed, bits) => match bits { + 8 => mir.gen_add(mir::Type::Byte, lhs, rhs), + 16 => mir.gen_add(mir::Type::Word, lhs, rhs), + 32 => mir.gen_add(mir::Type::DWord, lhs, rhs), + 64 => mir.gen_add(mir::Type::QWord, lhs, rhs), + 64.. => { + unimplemented!() + } + bits => { + let ty = mir::Type::from_bitsize_int(bits as u32); + + let sum = mir.gen_add(ty, lhs, rhs); + mir.gen_truncate(sum, ty, signed, bits) + } + }, + Type2::Binary32 => mir.gen_add(mir::Type::SinglePrecision, lhs, rhs), + Type2::Binary64 => mir.gen_add(mir::Type::DoublePrecision, lhs, rhs), + Type2::Pointer => mir.gen_add(mir::Type::QWord, lhs, rhs), + _ => unreachable!(), + } + } + Inst::Sub(ty) => { + let (src, dst) = data.unwrap().as_lhs_rhs(); + let lhs = *mapping.get(&src).unwrap(); + let rhs = *mapping.get(&dst).unwrap(); + + match ty { + Type2::Integral(signed, bits) => match bits { + 8 => mir.gen_sub(mir::Type::Byte, lhs, rhs), + 16 => mir.gen_sub(mir::Type::Word, lhs, rhs), + 32 => mir.gen_sub(mir::Type::DWord, lhs, rhs), + 64 => mir.gen_sub(mir::Type::QWord, lhs, rhs), + 64.. => { + unimplemented!() + } + bits => { + let ty = mir::Type::from_bitsize_int(bits as u32); + + let sum = mir.gen_sub(ty, lhs, rhs); + mir.gen_truncate(sum, ty, signed, bits) + } + }, + Type2::Binary32 => mir.gen_sub(mir::Type::SinglePrecision, lhs, rhs), + Type2::Binary64 => mir.gen_sub(mir::Type::DoublePrecision, lhs, rhs), + Type2::Pointer => mir.gen_sub(mir::Type::QWord, lhs, rhs), + _ => unreachable!(), + } + } + Inst::Mul(ty) => { + let (src, dst) = data.unwrap().as_lhs_rhs(); + let lhs = *mapping.get(&src).unwrap(); + let rhs = *mapping.get(&dst).unwrap(); + + match ty { + Type2::Integral(signed, bits) => match bits { + 8 => mir.gen_mul(mir::Type::Byte, signed, lhs, rhs), + 16 => mir.gen_mul(mir::Type::Word, signed, lhs, rhs), + 32 => mir.gen_mul(mir::Type::DWord, signed, lhs, rhs), + 64 => mir.gen_mul(mir::Type::QWord, signed, lhs, rhs), + 64.. => { + unimplemented!() + } + bits => { + let ty = mir::Type::from_bitsize_int(bits as u32); + + let sum = mir.gen_mul(ty, signed, lhs, rhs); + mir.gen_truncate(sum, ty, signed, bits) + } + }, + Type2::Binary32 => { + mir.gen_mul_unsigned(mir::Type::SinglePrecision, lhs, rhs) + } + Type2::Binary64 => { + mir.gen_mul_unsigned(mir::Type::DoublePrecision, lhs, rhs) + } + _ => unreachable!(), + } + } + Inst::Div(ty) => { + let (src, dst) = data.unwrap().as_lhs_rhs(); + let lhs = *mapping.get(&src).unwrap(); + let rhs = *mapping.get(&dst).unwrap(); + + match ty { + Type2::Integral(signed, bits) => match bits { + 8 => mir.gen_div(mir::Type::Byte, signed, lhs, rhs), + 16 => mir.gen_div(mir::Type::Word, signed, lhs, rhs), + 32 => mir.gen_div(mir::Type::DWord, signed, lhs, rhs), + 64 => mir.gen_div(mir::Type::QWord, signed, lhs, rhs), + 64.. => { + unimplemented!() + } + bits => { + let ty = mir::Type::from_bitsize_int(bits as u32); + + let sum = mir.gen_div(ty, signed, lhs, rhs); + mir.gen_truncate(sum, ty, signed, bits) + } + }, + Type2::Binary32 => { + mir.gen_div_unsigned(mir::Type::SinglePrecision, lhs, rhs) + } + Type2::Binary64 => { + mir.gen_div_unsigned(mir::Type::DoublePrecision, lhs, rhs) + } + _ => unreachable!(), + } + } + Inst::Rem(ty) => { + let (src, dst) = data.unwrap().as_lhs_rhs(); + let lhs = *mapping.get(&src).unwrap(); + let rhs = *mapping.get(&dst).unwrap(); + + match ty { + Type2::Integral(signed, bits) => match bits { + 8 => mir.gen_rem(mir::Type::Byte, signed, lhs, rhs), + 16 => mir.gen_rem(mir::Type::Word, signed, lhs, rhs), + 32 => mir.gen_rem(mir::Type::DWord, signed, lhs, rhs), + 64 => mir.gen_rem(mir::Type::QWord, signed, lhs, rhs), + 64.. => { + unimplemented!() + } + bits => { + let ty = mir::Type::from_bitsize_int(bits as u32); + + let sum = mir.gen_rem(ty, signed, lhs, rhs); + mir.gen_truncate(sum, ty, signed, bits) + } + }, + Type2::Binary32 => { + mir.gen_rem_unsigned(mir::Type::SinglePrecision, lhs, rhs) + } + Type2::Binary64 => { + mir.gen_rem_unsigned(mir::Type::DoublePrecision, lhs, rhs) + } + _ => unreachable!(), + } + } + Inst::BitAnd(ty) => { + let (src, dst) = data.unwrap().as_lhs_rhs(); + let lhs = *mapping.get(&src).unwrap(); + let rhs = *mapping.get(&dst).unwrap(); + + match ty { + Type2::Integral(signed, bits) => match bits { + 8 => mir.gen_bitand(mir::Type::Byte, lhs, rhs), + 16 => mir.gen_bitand(mir::Type::Word, lhs, rhs), + 32 => mir.gen_bitand(mir::Type::DWord, lhs, rhs), + 64 => mir.gen_bitand(mir::Type::QWord, lhs, rhs), + 64.. => { + unimplemented!() + } + bits => { + let ty = mir::Type::from_bitsize_int(bits as u32); + + let sum = mir.gen_bitand(ty, lhs, rhs); + mir.gen_truncate(sum, ty, signed, bits) + } + }, + _ => unreachable!(), + } + } + Inst::BitOr(ty) => { + let (src, dst) = data.unwrap().as_lhs_rhs(); + let lhs = *mapping.get(&src).unwrap(); + let rhs = *mapping.get(&dst).unwrap(); + + match ty { + Type2::Integral(signed, bits) => match bits { + 8 => mir.gen_bitor(mir::Type::Byte, lhs, rhs), + 16 => mir.gen_bitor(mir::Type::Word, lhs, rhs), + 32 => mir.gen_bitor(mir::Type::DWord, lhs, rhs), + 64 => mir.gen_bitor(mir::Type::QWord, lhs, rhs), + 64.. => { + unimplemented!() + } + bits => { + let ty = mir::Type::from_bitsize_int(bits as u32); + + let sum = mir.gen_bitor(ty, lhs, rhs); + mir.gen_truncate(sum, ty, signed, bits) + } + }, + _ => unreachable!(), + } + } + Inst::BitXOr(ty) => { + let (src, dst) = data.unwrap().as_lhs_rhs(); + let lhs = *mapping.get(&src).unwrap(); + let rhs = *mapping.get(&dst).unwrap(); + + match ty { + Type2::Integral(signed, bits) => match bits { + 8 => mir.gen_bitxor(mir::Type::Byte, lhs, rhs), + 16 => mir.gen_bitxor(mir::Type::Word, lhs, rhs), + 32 => mir.gen_bitxor(mir::Type::DWord, lhs, rhs), + 64 => mir.gen_bitxor(mir::Type::QWord, lhs, rhs), + 64.. => { + unimplemented!() + } + bits => { + let ty = mir::Type::from_bitsize_int(bits as u32); + + let sum = mir.gen_bitxor(ty, lhs, rhs); + mir.gen_truncate(sum, ty, signed, bits) + } + }, + _ => unreachable!(), + } + } + Inst::ShiftLeft(ty) => { + let (src, dst) = data.unwrap().as_lhs_rhs(); + let lhs = *mapping.get(&src).unwrap(); + let rhs = *mapping.get(&dst).unwrap(); + + match ty { + Type2::Integral(signed, bits) => match bits { + 8 => mir.gen_shl(mir::Type::Byte, lhs, rhs), + 16 => mir.gen_shl(mir::Type::Word, lhs, rhs), + 32 => mir.gen_shl(mir::Type::DWord, lhs, rhs), + 64 => mir.gen_shl(mir::Type::QWord, lhs, rhs), + 64.. => { + unimplemented!() + } + bits => { + let ty = mir::Type::from_bitsize_int(bits as u32); + + let sum = mir.gen_shl(ty, lhs, rhs); + mir.gen_truncate(sum, ty, signed, bits) + } + }, + _ => unreachable!(), + } + } + Inst::ShiftRight(ty) => { + let (src, dst) = data.unwrap().as_lhs_rhs(); + let lhs = *mapping.get(&src).unwrap(); + let rhs = *mapping.get(&dst).unwrap(); + + match ty { + Type2::Integral(signed, bits) => match bits { + 8 | 16 | 32 | 64 => { + let ty = mir::Type::from_bitsize_int(bits as u32); + if signed { + mir.gen_sar(ty, lhs, rhs) + } else { + mir.gen_shr(ty, lhs, rhs) + } + } + 64.. => { + unimplemented!() + } + bits => { + let ty = mir::Type::from_bitsize_int(bits as u32); + + let sum = if signed { + mir.gen_sar(ty, lhs, rhs) + } else { + mir.gen_shr(ty, lhs, rhs) + }; + + mir.gen_truncate(sum, ty, signed, bits) + } + }, + _ => unreachable!(), + } + } + Inst::Negate(ty) => { + let src = data.unwrap().as_u32(); + let src = *mapping.get(&src).unwrap(); + + match ty { + Type2::Integral(signed, bits) => match bits { + 8 => mir.gen_negate(mir::Type::Byte, src), + 16 => mir.gen_negate(mir::Type::Word, src), + 32 => mir.gen_negate(mir::Type::DWord, src), + 64 => mir.gen_negate(mir::Type::QWord, src), + 64.. => { + unimplemented!() + } + bits => { + let ty = mir::Type::from_bitsize_int(bits as u32); + + let sum = mir.gen_negate(ty, src); + mir.gen_truncate(sum, ty, signed, bits) + } + }, + _ => unreachable!(), + } + } + Inst::ReturnValue => { + let src = data.unwrap().as_u32(); + let src = *mapping.get(&src).unwrap(); + + mir.gen_ret_val(src) + } + Inst::Return => mir.gen_ret(), + _ => { + unimplemented!() + } + }; + + mapping.insert(ir_node, node); + } + + println!( + "{} mir:\n{}", + self.strings.get_str(name), + mir.display(&self.strings) + ); + } + + fn build(&mut self) { + loop { + let Some((inst, data)) = self.ir.next() else { + break; + }; + match inst { + Inst::FunctionStart => self.build_function(data.unwrap().as_index()), + _ => {} + } + } + } +} + #[cfg(test)] mod tests { use crate::lexer::Tokenizer; use super::*; + #[test] + fn mir() { + let src = " +fn inverse_sqrt(x: f32) -> f32 { + let three_halfs: f32 = 1.5f32; + let x2 = x * 0.5f32; + var y = x; + let i = 0x5f3759dfu32 - (*(&y as *u32) >> 1u32); + y = *(&i as *f32); + y = y * (three_halfs - (x2 * y * y)); + + return y; +} +"; + + let tokens = Tokenizer::new(src.as_bytes()).unwrap(); + + let mut tree = Tree::new(); + tree.parse(tokens.iter()).unwrap(); + + let mut buf = String::new(); + tree.render(&mut buf).unwrap(); + println!("AST:\n{buf}"); + + let mut ir = IR::new(); + let builder = ir.build(&mut tree); + let mut buf = String::new(); + builder.render(&mut buf).unwrap(); + println!("IR:\n{buf}"); + + let mut mir = MirBuilder::new(&ir, tree.strings); + mir.build(); + } + + #[test] + fn mir_u10() { + let src = " +fn u10(x: i10) -> i10 { + 5i10 * 3i10 +} +"; + + let tokens = Tokenizer::new(src.as_bytes()).unwrap(); + + let mut tree = Tree::new(); + tree.parse(tokens.iter()).unwrap(); + + let mut buf = String::new(); + tree.render(&mut buf).unwrap(); + println!("AST:\n{buf}"); + + let mut ir = IR::new(); + let builder = ir.build(&mut tree); + let mut buf = String::new(); + builder.render(&mut buf).unwrap(); + println!("IR:\n{buf}"); + + let mut mir = MirBuilder::new(&ir, tree.strings); + mir.build(); + } + #[test] fn ir() { let src = " fn main() -> u32 { let a: u32 = 0u32 + 3u32; - let ptr_a = &a; - return *ptr_a * 2u32; + let b = &a; + return *b * 2u32; } fn square(x: u32) -> u32 { @@ -1093,7 +1741,11 @@ fn square(x: u32) -> u32 { builder.render(&mut buf).unwrap(); println!("{buf}"); - let mut assembler = Assembler::from_ir(&ir, tree.strings); + let strings = tree.strings; + let mut mir = MirBuilder::new(&ir, strings.clone()); + mir.build(); + + let mut assembler = Assembler::from_ir(&ir, strings); assembler.assemble().unwrap(); let mut buf = String::new();