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?
This commit is contained in:
Janis 2024-08-25 03:09:54 +02:00
parent c8d51e8bcf
commit 010e6d2bec
6 changed files with 1262 additions and 70 deletions

View file

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

View file

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

530
src/mir.rs Normal file
View file

@ -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<u8> for Data {
fn from(value: u8) -> Self {
Data::imm8(value)
}
}
impl From<u16> for Data {
fn from(value: u16) -> Self {
Data::imm16(value)
}
}
impl From<u32> for Data {
fn from(value: u32) -> Self {
Data::imm32(value)
}
}
impl From<u64> 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<Inst>,
pub data: Vec<Data>,
}
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<W: core::fmt::Write>(
&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<W: core::fmt::Write>(
&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)
}
}

View file

@ -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<Node> {
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<Node> {
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<Node> {
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)?;

View file

@ -19,6 +19,7 @@ impl Index {
}
}
#[derive(Clone)]
pub struct StringTable {
bytes: Vec<u8>,
indices: BTreeMap<u64, Index>,

View file

@ -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<Width> {
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();
match src {
ImmRegMem::Reg(_, _) => {
writeln!(
func.branches.get_mut(&current_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(&current_branch).unwrap(),
"mov {}, {}",
src,
tmp_reg.display(Width::QWord),
)?;
writeln!(
func.branches.get_mut(&current_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(&reg);
@ -931,7 +1024,47 @@ impl<'a> Assembler<'a> {
registers.remove(&reg);
}
}
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(&current_branch).unwrap(),
"lea {}, {}",
src,
ImmRegMem::Reg(dst_reg, Width::QWord),
)?;
}
let offset = idx * ty.size();
if offset != 0 {
writeln!(
func.branches.get_mut(&current_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(&reg);
}
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(&current_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(&reg);
}
}
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(&current_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(&reg);
}
}
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::<u32, u32>::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();