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:
parent
c8d51e8bcf
commit
010e6d2bec
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
530
src/mir.rs
Normal 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)
|
||||
}
|
||||
}
|
|
@ -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)?;
|
||||
|
|
|
@ -19,6 +19,7 @@ impl Index {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct StringTable {
|
||||
bytes: Vec<u8>,
|
||||
indices: BTreeMap<u64, Index>,
|
||||
|
|
716
src/triples.rs
716
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<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();
|
||||
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::<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();
|
||||
|
|
Loading…
Reference in a new issue