Skip to content

Commit

Permalink
refactor(ir): simplify ir builder and error handling
Browse files Browse the repository at this point in the history
  • Loading branch information
JuniMay committed Feb 18, 2024
1 parent 4ebc98e commit f435b48
Show file tree
Hide file tree
Showing 8 changed files with 207 additions and 100 deletions.
4 changes: 4 additions & 0 deletions src/collections.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ where
self.nodes.contains_key(&key)
}

pub fn front(&self) -> Option<K> {
self.head
}

pub fn node(&self, key: K) -> Option<&N> {
self.nodes.get(&key)
}
Expand Down
59 changes: 58 additions & 1 deletion src/ir/builder.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::{error::Error, fmt};

use super::{
entities::{BlockData, FunctionData, FunctionKind, ValueData, ValueKind},
module::{DataFlowGraph, Module},
Expand Down Expand Up @@ -61,6 +63,34 @@ pub enum BuilderErr {
IncompatibleBlockArgType,
}

impl fmt::Display for BuilderErr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use BuilderErr::*;
match self {
ValueNotFound => write!(f, "value not found"),
BlockNotFound => write!(f, "block not found"),
InvalidType => write!(f, "invalid value type"),
InvalidKind => write!(f, "invalid value kind"),
InvalidMutability => write!(f, "invalid mutability"),
InvalidGlobalValue => write!(f, "invalid global value"),
InvalidLocalValue => write!(f, "invalid local value"),
IncompatibleType => write!(f, "incompatible value type"),
IncompatibleArraySize => write!(f, "incompatible array size"),
IncompatibleArrayElemType => write!(f, "incompatible array element type"),
IncompatibleStructFieldNumber => {
write!(f, "incompatible struct field number")
}
IncompatibleStructFieldType => write!(f, "incompatible struct field type"),
IncompatibleBlockArgNumber => {
write!(f, "incompatible block argument number")
}
IncompatibleBlockArgType => write!(f, "incompatible block argument type"),
}
}
}

impl Error for BuilderErr {}

pub trait QueryValueData {
/// Get the type of a value.
fn value_type(&self, value: Value) -> Result<Type, BuilderErr>;
Expand Down Expand Up @@ -108,6 +138,28 @@ pub trait ConstantBuilder: QueryValueData + AddValue {
self.add_value(ValueData::new(ty, ValueKind::Bytes(bytes)))
}

/// Build an integer constant of i32 type.
fn integer(&mut self, value: i32) -> Result<Value, BuilderErr> {
let bytes = value.to_le_bytes().to_vec();

// remove leading zeros
let bytes = bytes
.into_iter()
.rev()
.skip_while(|&b| b == 0)
.collect::<Vec<u8>>();

self.bytes(Type::mk_int(32), bytes)
}

/// Build a float constant.
///
/// This is a shorthand for `bytes` with the bytes of the float.
fn float(&mut self, value: f32) -> Result<Value, BuilderErr> {
let bytes = value.to_le_bytes().to_vec();
self.bytes(Type::mk_float(), bytes)
}

/// Build an array constant.
fn array(&mut self, ty: Type, values: Vec<Value>) -> Result<Value, BuilderErr> {
let (size, elem_type) = ty.as_array().ok_or(BuilderErr::InvalidType)?;
Expand Down Expand Up @@ -200,7 +252,12 @@ pub trait LocalValueBuilder: QueryDfgData + AddValue + ConstantBuilder {
}
}

self.add_value(Binary::new_value_data(lhs_type, op, lhs, rhs))
let res_type = match op {
BinaryOp::ICmp(_) | BinaryOp::FCmp(_) => Type::mk_int(1),
_ => lhs_type,
};

self.add_value(Binary::new_value_data(res_type, op, lhs, rhs))
}

/// Build a unary instruction.
Expand Down
24 changes: 23 additions & 1 deletion src/ir/layout.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::collections::HashMap;
use std::{collections::HashMap, error::Error, fmt};

use crate::collections::{BiLinkedList, BiLinkedListErr, BiLinkedNode};

Expand Down Expand Up @@ -113,6 +113,24 @@ pub enum LayoutOpErr {
InstNodeNotFound(Inst),
}

impl fmt::Display for LayoutOpErr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
LayoutOpErr::InstDuplicated(inst) => write!(f, "duplicated instruction: {:?}", inst),
LayoutOpErr::BlockDuplicated(block) => write!(f, "duplicated block: {:?}", block),
LayoutOpErr::ParentBlockNotFound(inst) => {
write!(f, "parent block not found for instruction: {:?}", inst)
}
LayoutOpErr::BlockNodeNotFound(block) => write!(f, "block node not found: {:?}", block),
LayoutOpErr::InstNodeNotFound(inst) => {
write!(f, "instruction node not found: {:?}", inst)
}
}
}
}

impl Error for LayoutOpErr {}

impl Layout {
pub fn new() -> Self {
Self {
Expand All @@ -121,6 +139,10 @@ impl Layout {
}
}

pub fn entry_block(&self) -> Option<Block> {
self.blocks.front()
}

pub fn blocks(&self) -> &BlockList {
&self.blocks
}
Expand Down
49 changes: 42 additions & 7 deletions src/ir/module.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use std::{
cell::RefCell,
collections::{HashMap, HashSet},
error::Error,
fmt,
hash::Hash,
rc::{Rc, Weak},
};
Expand Down Expand Up @@ -103,12 +105,15 @@ impl DataFlowGraph {

/// Get the name of a local or global value
pub fn value_name(&self, value: Value) -> String {
self.global_name_allocator
.upgrade()
.expect("global name allocator should be alive.")
.borrow_mut()
.try_get(value)
.unwrap_or_else(|| self.value_name_allocator.borrow_mut().get(value))
if let Some(_) = self.local_value_data(value) {
self.value_name_allocator.borrow_mut().get(value)
} else {
self.global_name_allocator
.upgrade()
.expect("global name allocator should be alive.")
.borrow_mut()
.get(value)
}
}

/// Get the name of a block
Expand Down Expand Up @@ -244,8 +249,27 @@ impl Module {
value
}

pub(super) fn add_function(&mut self, value_data: ValueData, function_data: FunctionData) -> Function {
pub(super) fn add_function(
&mut self,
value_data: ValueData,
function_data: FunctionData,
) -> Function {
let function = Value::new(self.allocate_id());
let function_name = function_data.name().to_string();

if function_name.starts_with(GLOBAL_PREFIX) {
self.name_allocator
.borrow_mut()
.assign(function, function_name)
.unwrap();
} else {
let name = format!("{}{}", GLOBAL_PREFIX, function_name);
self.name_allocator
.borrow_mut()
.assign(function, name)
.unwrap();
}

self.globals.borrow_mut().insert(function, value_data);
self.functions.insert(function.into(), function_data);

Expand Down Expand Up @@ -321,6 +345,17 @@ pub enum NameAllocErr {
NameDuplicated,
}

impl fmt::Display for NameAllocErr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::KeyDuplicated => write!(f, "key is already assigned or allocated"),
Self::NameDuplicated => write!(f, "name is already assigned or allocated"),
}
}
}

impl Error for NameAllocErr {}

impl<T> NameAllocator<T>
where
T: Hash + Eq + Copy,
Expand Down
10 changes: 8 additions & 2 deletions src/ir/pass.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
use super::{entities::FunctionData, module::Module, values::Function};

pub trait GlobalPass {
fn run(&mut self, module: &mut Module);
type Ok;
type Err;

fn run(&mut self, module: &mut Module) -> Result<Self::Ok, Self::Err>;
}

pub trait LocalPass {
fn run(&mut self, function: Function, data: &mut FunctionData);
type Ok;
type Err;

fn run(&mut self, function: Function, data: &mut FunctionData) -> Result<Self::Ok, Self::Err>;
}
8 changes: 8 additions & 0 deletions src/ir/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,14 @@ impl Type {
Type::make(TypeKind::Int(bits))
}

pub fn mk_i32() -> Type {
Type::mk_int(32)
}

pub fn mk_i1() -> Type {
Type::mk_int(1)
}

pub fn mk_void() -> Type {
Type::make(TypeKind::Void)
}
Expand Down
Loading

0 comments on commit f435b48

Please sign in to comment.