#![allow(dead_code)]
mod value;
use std::ops::{Rem, Sub};
use crate::checker::types::TypeId;
pub use value::*;
#[derive(Debug, Clone)]
pub struct IrBind {
pub name: String,
pub kind: TypeId,
}
impl IrBind {
pub fn new(name: String, kind: TypeId) -> Self {
Self { name, kind }
}
}
#[derive(Debug, Clone)]
pub enum Instr {
Add(BinInstr), Sub(BinInstr), Mul(BinInstr), Div(BinInstr), Mod(BinInstr),
Neg(BinInstr), Not(BinInstr),
CmpEq(BinInstr), CmpNe(BinInstr), CmpLt(BinInstr), CmpGt(BinInstr), CmpLe(BinInstr), CmpGe(BinInstr),
And(BinInstr), Or(BinInstr), Shl(BinInstr), Shr(BinInstr),
Jmp(JmpInstr), JmpIf(JmpIfInstr),
Ret(Option<IrBasicValue>), Call(CallInstr),
Load(UnInstr), Mov(UnInstr), Drop(IrBasicValue), Set(UnInstr), Salloc(SallocInstr), Halloc(UnInstr),
Getptr(GetPtrInstr), }
#[derive(Debug, Clone)]
pub struct GetPtrInstr {
pub dest: IrBasicValue,
pub self_base: IrBasicValue,
pub self_name: String,
pub offset: usize,
}
impl GetPtrInstr {
pub fn new(self_name: String, self_ptr: IrBasicValue, offset: usize, dest: IrBasicValue) -> Self {
Self { dest, self_base: self_ptr, self_name, offset }
}
}
impl From<GetPtrInstr> for Instr {
fn from(value: GetPtrInstr) -> Self {
Instr::Getptr(value)
}
}
#[derive(Debug, Clone)]
pub struct SallocInstr {
pub dest: IrBasicValue,
pub size: TypeId,
}
impl SallocInstr {
pub fn new(dest: IrBasicValue, size: TypeId) -> Self {
Self { dest, size }
}
}
impl From<SallocInstr> for Instr {
fn from(value: SallocInstr) -> Self {
Instr::Salloc(value)
}
}
#[derive(Debug, Clone)]
pub struct BinInstr {
pub dest: IrBasicValue,
pub left: IrBasicValue,
pub right: IrBasicValue,
}
impl BinInstr {
pub fn new(dest: IrBasicValue, left: IrBasicValue, right: IrBasicValue) -> Self {
Self { dest, left, right }
}
}
#[derive(Debug, Clone)]
pub struct UnInstr {
pub dest: IrBasicValue,
pub src: IrBasicValue,
}
impl UnInstr {
pub fn new(dest: IrBasicValue, src: IrBasicValue) -> Self {
Self { dest, src }
}
}
#[derive(Debug, Clone)]
pub struct JmpInstr {
pub label: usize,
}
impl JmpInstr {
pub fn new(label: usize) -> Self {
Self { label }
}
pub fn llvm_label(&self) -> String {
format!("lx{}", self.label)
}
pub fn display_label(&self) -> String {
format!("l_{}", self.label)
}
}
#[derive(Debug, Clone)]
pub struct JmpIfInstr {
pub cond: IrBasicValue,
pub true_label: usize,
pub false_label: usize,
}
impl JmpIfInstr {
pub fn new(cond: IrBasicValue, true_label: usize, false_label: usize) -> Self {
Self { cond, true_label, false_label }
}
pub fn display_true_label(&self) -> String {
format!("l_{}", self.true_label)
}
pub fn display_false_label(&self) -> String {
if self.false_label == 1 {
return "entry".to_string();
}
format!("l_{}", self.false_label)
}
pub fn llvm_true_label(&self) -> String {
if self.true_label == 1 {
return "entry".to_string();
}
format!("lx{}", self.true_label)
}
pub fn llvm_false_label(&self) -> String {
format!("lx{}", self.false_label)
}
}
#[derive(Debug, Clone)]
pub struct CallInstr {
pub dest: IrBasicValue,
pub callee: String,
pub ret_id: TypeId,
pub args: Vec<IrBasicValue>,
}
impl CallInstr {
pub fn new(dest: IrBasicValue, callee: String, ret_id: TypeId, args: Vec<IrBasicValue>) -> Self {
Self { dest, callee, ret_id, args }
}
}
#[derive(Debug, Clone)]
pub struct IrBlock {
pub label: usize,
pub instrs: Vec<Instr>,
}
impl Default for IrBlock {
fn default() -> Self {
Self::new(1)
}
}
impl IrBlock {
pub fn new(label: usize) -> Self {
Self { label, instrs: Vec::new() }
}
pub fn add_instr(&mut self, instr: Instr) {
self.instrs.push(instr);
}
pub fn format_label(&self) -> String {
format!("l{}", self.label)
}
pub fn llvm_name(&self) -> String {
if self.label == 1 {
return "entry".to_string();
}
format!("lx{}", self.label)
}
}
#[derive(Debug, Clone)]
pub struct Function {
pub extern_function: bool,
pub name: String,
pub comptime: bool,
pub variadic_args: bool,
pub ret: TypeId,
pub args: Vec<IrBasicValue>,
pub blocks: Vec<IrBlock>,
}
impl Function {
pub fn new(name: String, comptime: bool, args: Vec<IrBasicValue>, ret: TypeId) -> Self {
Self {
name,
comptime,
args,
blocks: Vec::new(),
ret,
variadic_args: false,
extern_function: false,
}
}
pub fn is_main(&self) -> bool {
self.name == "main"
}
pub fn is_variadic_args(&self) -> bool {
self.variadic_args
}
pub fn is_extern_function(&self) -> bool {
self.extern_function
}
pub fn as_extern_function(&mut self, variadic_args: bool) {
self.extern_function = true;
self.variadic_args = variadic_args;
}
pub fn add_block(&mut self, block: IrBlock) {
self.blocks.push(block);
}
pub fn extend_blocks(&mut self, blocks: Vec<IrBlock>) {
self.blocks.extend(blocks);
}
}
pub struct Struct {
pub fields: Vec<TypeId>,
pub name: Option<String>,
pub size: usize,
}
impl Struct {
pub fn new(fields: Vec<TypeId>) -> Self {
Self { fields, name: None, size: 0 }
}
pub fn new_with_name(fields: Vec<TypeId>, name: impl Into<String>) -> Self {
Self { fields, name: Some(name.into()), size: 0 }
}
pub fn with_capacity(capacity: usize) -> Self {
Self { fields: Vec::with_capacity(capacity), name: None, size: 0 }
}
pub fn set_name(&mut self, name: impl Into<String>) {
self.name = Some(name.into());
}
pub fn add_field(&mut self, field: TypeId) -> usize {
let field_size = field.get_size();
let field_align = field.get_align();
if self.size.rem(field_align).ne(&0) {
self.size += field_align.sub(self.size.rem(field_align));
}
let index = self.fields.len();
self.fields.push(field);
self.size += field_size;
index
}
pub fn lazy_size(&mut self) {
let max_align = self.fields.iter().map(|field| field.get_align()).max().unwrap_or(1);
if self.size.rem(max_align).ne(&0) {
self.size += max_align.sub(self.size.rem(max_align));
}
}
pub fn get_fields(&self) -> &[TypeId] {
&self.fields
}
pub fn get_field(&mut self, index: usize) -> Option<&mut TypeId> {
self.fields.get_mut(index)
}
}
impl Default for Struct {
fn default() -> Self {
Self::new(Vec::new())
}
}
pub struct IR {
pub functions: Vec<Function>,
pub structs: Vec<Struct>,
}
impl Default for IR {
fn default() -> Self {
Self::new()
}
}
impl IR {
pub fn new() -> Self {
Self { functions: Vec::new(), structs: Vec::new() }
}
pub fn add_function(&mut self, function: Function) {
self.functions.push(function);
}
pub fn add_struct(&mut self, struct_: Struct) {
self.structs.push(struct_);
}
}
impl From<CallInstr> for Instr {
fn from(value: CallInstr) -> Self {
Instr::Call(value)
}
}
impl From<JmpIfInstr> for Instr {
fn from(value: JmpIfInstr) -> Self {
Instr::JmpIf(value)
}
}
impl From<JmpInstr> for Instr {
fn from(value: JmpInstr) -> Self {
Instr::Jmp(value)
}
}