Skip to content

Commit

Permalink
Docwork
Browse files Browse the repository at this point in the history
  • Loading branch information
Y-Nak committed Sep 11, 2024
1 parent 35f6052 commit 1be6d6e
Show file tree
Hide file tree
Showing 2 changed files with 106 additions and 15 deletions.
68 changes: 53 additions & 15 deletions crates/ir/src/inst/inst_set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@ use super::{basic, Inst};

use macros::define_inst_set_base;

pub(super) mod sealed {
/// This trait has two roles,
/// 1. works as a sealed trait.
/// 2. ensure that an `Inst` is definitely registered to the `InstGroup`.
pub trait Registered {}
}

// All instructions defined in the IR must be listed(otherwise, you'll get a compile error).
define_inst_set_base! {
/// This trait is used to determine whether a certain instruction set includes a specific inst in runtime.
/// If a certain instruction set `IS` implements `HasInst<I>`,
/// the corresponding `has_i(&self) -> Option<&dyn HasInst<I>>` method always returns `Some`.
///
/// Since all instruction set implements `HasInst<Inst>` if it containst `Inst`,
/// this trait is naturally intened to be used as a trait object.
///
/// NOTE: Do NOT implement this trait manually, use `sonatina-macro::inst_set` instead.
trait InstSetBase {
basic::Not,
basic::Neg,
basic::Add,
Expand Down Expand Up @@ -47,7 +48,37 @@ define_inst_set_base! {
basic::Phi,
basic::Nop,
}
}

/// This trait provides the concrete mapping from `Inst` to corresponding enum variant.
/// All instruction set that are defined by `sonatina_macros::inst_set` automatically defines an enum which represents all instructions in the set.
/// e.g.
///
/// ```rust,ignore
/// use sonatina_ir::inst::basic::*;
/// #[inst_set(InstKind = "InstKind")]
/// struct InstSet(Add, Sub);
/// ```
/// defines
///
/// ```rust
/// use sonatina_ir::inst::basic::*;
/// enum InstKind<'i> {
/// Add(&'i Add),
/// Sub(&'i Sub),
/// }
/// enum InstKindMut<'i> {
/// Add(&'i mut Add),
/// Sub(&'i mut Sub),
/// }
/// ```
///
/// Assuming that the all instructions are created with this instruction set,
/// the cast(resolution) from dynamic inst object to this enum always succeed.
///
/// This macro provides the way to these safe downcast, and allow us to focus on the
/// restricted concrete instruction set, instead of "all possible" instructions.
///
pub trait InstSetExt: InstSetBase {
type InstKind<'i>;
type InstKindMut<'i>;
Expand All @@ -63,7 +94,7 @@ mod tests {
use basic::*;
use macros::inst_set;

#[inst_set(InstKind = "TestInstSetKind")]
#[inst_set(InstKind = "TestInstKind")]
struct TestInstSet(Add, Sub, Not, Phi, Jump);

#[test]
Expand Down Expand Up @@ -106,17 +137,24 @@ mod tests {
insts.push(Box::new(not));

let resolved = inst_set.resolve_inst(insts[0].as_ref());
assert!(matches!(resolved, TestInstSetKind::Add(_)));
assert!(matches!(resolved, TestInstKind::Add(_)));
let resolved = inst_set.resolve_inst(insts[1].as_ref());
assert!(matches!(resolved, TestInstSetKind::Sub(_)));
assert!(matches!(resolved, TestInstKind::Sub(_)));
let resolved = inst_set.resolve_inst(insts[2].as_ref());
assert!(matches!(resolved, TestInstSetKind::Not(_)));
assert!(matches!(resolved, TestInstKind::Not(_)));

let resolved = inst_set.resolve_inst_mut(insts[0].as_mut());
assert!(matches!(resolved, TestInstSetKindMut::Add(_)));
assert!(matches!(resolved, TestInstKindMut::Add(_)));
let resolved = inst_set.resolve_inst_mut(insts[1].as_mut());
assert!(matches!(resolved, TestInstSetKindMut::Sub(_)));
assert!(matches!(resolved, TestInstKindMut::Sub(_)));
let resolved = inst_set.resolve_inst_mut(insts[2].as_mut());
assert!(matches!(resolved, TestInstSetKindMut::Not(_)));
assert!(matches!(resolved, TestInstKindMut::Not(_)));
}
}

pub(super) mod sealed {
/// This trait has two roles,
/// 1. works as a sealed trait.
/// 2. ensure that an `Inst` is definitely registered to the `InstGroup`.
pub trait Registered {}
}
53 changes: 53 additions & 0 deletions crates/macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,30 @@ mod inst;
mod inst_set;
mod inst_set_base;

/// A derive macro to define each instruction type.
/// This macro dervies the `Isnt` trait for the macro,
/// and implements a consructor and acccessors for each fields.
///
/// # Usage
/// ```rust, ignore
/// use sonatina_macros::Inst;
///
/// #[derive(Inst)]
/// #[inst(has_side_effect)]
/// struct MStore {
/// #[inst(value)]
/// lhs: Value,
/// #[inst(value)]
/// rhs: Value,
/// }
/// ```
///
/// # Arguments
/// - `has_side_effect`: Marks the instruction as having a side effect.
/// - `value`: Marks the field that contains value,
/// the specified field must implements `sonatina-ir::inst::ValueVisitable` trait.
///
/// # Usage
#[proc_macro_derive(Inst, attributes(inst))]
pub fn derive_inst(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
inst::derive_inst(item)
Expand All @@ -12,6 +36,27 @@ pub fn define_inst_set_base(input: proc_macro::TokenStream) -> proc_macro::Token
inst_set_base::define_inst_set_base(input)
}

/// A macro to define an instruction set that is specific to an target arch.
/// In sonatina, an InstructionSet is defined as a type that implements `HasInst<{Inst}>` for all `{Inst}` it contains,
/// and also implements `InstSetBase` and `InstSetExt`.
/// This macro automatically implements these traits and modify the type definition to enable an effective cast of instruction.
///
/// # Usage
/// ```rust, ignore
/// #[inst_set(InstKind = "TestInstKind")]
/// struct TestInstSet(Add, Sub);
/// ```
///
/// # Arguments
/// ## InstKind = "TestInstKind"`
/// This arguments specifies an `enum` used in `InstSetExt::InstKind`. This enum is also generated automatically.
/// In the abobe example, the below enum is generated, and can be obtained via `InstSetExt::resolve_inst` method.
/// ```rust, ignore
/// enum TestInstKind<'i> {
/// Add(&'i Add),
/// Sub(&'i Sub),
/// }
/// ```
#[proc_macro_attribute]
pub fn inst_set(
attr: proc_macro::TokenStream,
Expand All @@ -20,6 +65,14 @@ pub fn inst_set(
inst_set::define_inst_set(attr, input)
}

/// Converts a given string to snake case.
///
/// The function iterates through each character in the string. If the character is uppercase,
/// it checks if the previous character was also uppercase. If it wasn't, it adds an underscore before
/// the current character. It then converts the character to lowercase and adds it to the result string.
/// e.g.,
/// * `FooBar -> foo_bar`
/// * `FooBAR -> foo_bar`
fn convert_to_snake(s: &str) -> String {
let mut res = String::new();
let mut is_upper = false;
Expand Down

0 comments on commit 1be6d6e

Please sign in to comment.