Skip to content

Commit

Permalink
refactor: improve behavior of frontend config
Browse files Browse the repository at this point in the history
  • Loading branch information
bitwalker committed Aug 10, 2024
1 parent d028575 commit 0230276
Show file tree
Hide file tree
Showing 30 changed files with 1,367 additions and 444 deletions.
109 changes: 66 additions & 43 deletions Cargo.lock

Large diffs are not rendered by default.

20 changes: 11 additions & 9 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ Inflector = "0.11"
intrusive-collections = "0.9"
inventory = "0.3"
log = "0.4"
miette = { version = "7.1.0", git = "https://github.com/bitwalker/miette", branch = "no-std" }
#miette = { package = "miden-miette", version = "7.1.1" }
miette = { version = "7.1", git = "https://github.com/bitwalker/miette", branch = "no-std" }
paste = "1.0"
parking_lot = "0.12"
parking_lot_core = "0.9"
Expand All @@ -64,14 +65,19 @@ smallvec = { version = "1.13", features = [
"drain_filter",
] }
smallstr = { version = "0.3", features = ["union"] }
#thiserror = { package = "miden-thiserror", version = "1.0" }
thiserror = { version = "1.0", git = "https://github.com/bitwalker/thiserror", branch = "no-std" }
toml = { version = "0.8", features = ["preserve_order"] }
derive_more = "0.99"
indexmap = "2.2"
miden-assembly = { git = "https://github.com/0xPolygonMiden/miden-vm", rev = "b4e1f3abf84c0c982b3a0ff83bb7568d2ba7ee88" }
miden-core = { git = "https://github.com/0xPolygonMiden/miden-vm", rev = "b4e1f3abf84c0c982b3a0ff83bb7568d2ba7ee88" }
miden-processor = { git = "https://github.com/0xPolygonMiden/miden-vm", rev = "b4e1f3abf84c0c982b3a0ff83bb7568d2ba7ee88" }
miden-stdlib = { git = "https://github.com/0xPolygonMiden/miden-vm", rev = "b4e1f3abf84c0c982b3a0ff83bb7568d2ba7ee88" }
#miden-assembly = { version = "0.10" }
#miden-core = { version = "0.10" }
#miden-processor = { version = "0.10" }
#miden-stdlib = { version = "0.10" }
miden-assembly = { git = "https://github.com/0xPolygonMiden/miden-vm", rev = "828557c28ca1d159bfe42195e7ea73256ce4aa06" }
miden-core = { git = "https://github.com/0xPolygonMiden/miden-vm", rev = "828557c28ca1d159bfe42195e7ea73256ce4aa06" }
miden-processor = { git = "https://github.com/0xPolygonMiden/miden-vm", rev = "828557c28ca1d159bfe42195e7ea73256ce4aa06" }
miden-stdlib = { git = "https://github.com/0xPolygonMiden/miden-vm", rev = "828557c28ca1d159bfe42195e7ea73256ce4aa06" }
midenc-codegen-masm = { path = "codegen/masm" }
miden-diagnostics = "0.1"
midenc-hir = { version = "0.0.1", path = "hir" }
Expand All @@ -89,10 +95,6 @@ miden-integration-tests = { version = "0.0.0", path = "tests/integration" }
wat = "1.0.69"
blake3 = "1.5"

[patch.crates-io]
thiserror = { git = "https://github.com/bitwalker/thiserror", branch = "no-std" }
miette = { git = "https://github.com/bitwalker/miette", branch = "no-std" }

[profile.dev]
lto = false
# Needed for 'inventory' to work
Expand Down
75 changes: 75 additions & 0 deletions codegen/masm/src/compiler/masm.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
use miden_assembly::library::Library as CompiledLibrary;
use midenc_hir::Symbol;
use midenc_session::{diagnostics::Report, Emit, OutputMode, OutputType, Session};

use crate::{Library, MastArtifact, Module, Program};

/// The artifact produced by lowering an [hir::Program] to Miden Assembly
///
/// This type is used in compilation pipelines to abstract over the type of output requested.
pub enum MasmArtifact {
/// An executable program, with a defined entrypoint
Executable(Box<Program>),
/// A library, linkable into a program as needed
Library(Box<Library>),
}

impl MasmArtifact {
pub fn assemble(&self, session: &Session) -> Result<MastArtifact, Report> {
match self {
Self::Executable(program) => program.assemble(session).map(MastArtifact::Executable),
Self::Library(library) => library.assemble(session).map(MastArtifact::Library),
}
}

/// Get an iterator over the modules in this library
pub fn modules(&self) -> impl Iterator<Item = &Module> + '_ {
match self {
Self::Executable(ref program) => program.library().modules(),
Self::Library(ref lib) => lib.modules(),
}
}

pub fn insert(&mut self, module: Box<Module>) {
match self {
Self::Executable(ref mut program) => program.insert(module),
Self::Library(ref mut lib) => lib.insert(module),
}
}

pub fn link_library(&mut self, lib: CompiledLibrary) {
match self {
Self::Executable(ref mut program) => program.link_library(lib),
Self::Library(ref mut library) => library.link_library(lib),
}
}

pub fn unwrap_executable(self) -> Box<Program> {
match self {
Self::Executable(program) => program,
Self::Library(_) => panic!("tried to unwrap a mast library as an executable"),
}
}
}

impl Emit for MasmArtifact {
fn name(&self) -> Option<Symbol> {
None
}

fn output_type(&self, _mode: OutputMode) -> OutputType {
OutputType::Masm
}

fn write_to<W: std::io::Write>(
&self,
writer: W,
mode: OutputMode,
session: &Session,
) -> std::io::Result<()> {
match self {
Self::Executable(ref prog) => prog.write_to(writer, mode, session),
Self::Library(ref lib) => lib.write_to(writer, mode, session),
}
}
}
56 changes: 56 additions & 0 deletions codegen/masm/src/compiler/mast.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
use std::sync::Arc;

use miden_assembly::library::Library as CompiledLibrary;
use midenc_hir::Symbol;
use midenc_session::{Emit, OutputMode, OutputType, Session};

/// The artifact produced by lowering a [Program] to a Merkelized Abstract Syntax Tree
///
/// This type is used in compilation pipelines to abstract over the type of output requested.
pub enum MastArtifact {
/// A MAST artifact which can be executed by the VM directly
Executable(Arc<miden_core::Program>),
/// A MAST artifact which can be used as a dependency by a [miden_core::Program]
Library(Arc<CompiledLibrary>),
}

impl MastArtifact {
pub fn unwrap_program(self) -> Arc<miden_core::Program> {
match self {
Self::Executable(prog) => prog,
Self::Library(_) => panic!("attempted to unwrap 'mast' library as program"),
}
}
}

impl Emit for MastArtifact {
fn name(&self) -> Option<Symbol> {
None
}

fn output_type(&self, mode: OutputMode) -> OutputType {
match mode {
OutputMode::Text => OutputType::Mast,
OutputMode::Binary => OutputType::Masl,
}
}

fn write_to<W: std::io::Write>(
&self,
writer: W,
mode: OutputMode,
session: &Session,
) -> std::io::Result<()> {
match self {
Self::Executable(ref prog) => {
if matches!(mode, OutputMode::Binary) {
log::warn!(
"unable to write 'masl' output type for miden_core::Program: skipping.."
);
}
prog.write_to(writer, mode, session)
}
Self::Library(ref lib) => lib.write_to(writer, mode, session),
}
}
}
154 changes: 154 additions & 0 deletions codegen/masm/src/compiler/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
mod masm;
mod mast;

use midenc_hir::{
self as hir,
pass::{RewritePass, RewriteSet},
};
use midenc_session::{diagnostics::Report, Session};

pub use self::{masm::MasmArtifact, mast::MastArtifact};
use crate::{intrinsics, ConvertHirToMasm, Program};

pub type CompilerResult<T> = Result<T, Report>;

/// [MasmCompiler] is a compiler from Miden IR to MASM IR, an intermediate representation
/// of Miden Assembly which is used within the Miden compiler framework for various purposes,
/// and can be emitted directly to textual Miden Assembly.
///
/// The [MasmCompiler] is designed to compile a [midenc_hir::Program]
///
/// can be used to take a linked [midenc_hir::Program] and
/// compile it to MASM IR, an intermediate representation of Miden Assembly
/// used within the compiler.
pub struct MasmCompiler<'a> {
session: &'a Session,
analyses: hir::pass::AnalysisManager,
}
impl<'a> MasmCompiler<'a> {
pub fn new(session: &'a Session) -> Self {
Self {
session,
analyses: hir::pass::AnalysisManager::new(),
}
}

/// Compile an [hir::Program] that has been linked and is ready to be compiled.
pub fn compile(&mut self, mut input: Box<hir::Program>) -> CompilerResult<MasmArtifact> {
use midenc_hir::pass::ConversionPass;

let mut rewrites = default_rewrites([], self.session);

let modules = input.modules_mut().take();
for mut module in modules.into_iter() {
rewrites.apply(&mut module, &mut self.analyses, self.session)?;
input.modules_mut().insert(module);
}

let mut convert_to_masm = ConvertHirToMasm::<hir::Program>::default();
let mut artifact = convert_to_masm.convert(input, &mut self.analyses, self.session)?;

// Ensure intrinsics modules are linked
artifact.insert(Box::new(
intrinsics::load("intrinsics::mem", &self.session.source_manager)
.expect("undefined intrinsics module"),
));
artifact.insert(Box::new(
intrinsics::load("intrinsics::i32", &self.session.source_manager)
.expect("undefined intrinsics module"),
));
artifact.insert(Box::new(
intrinsics::load("intrinsics::i64", &self.session.source_manager)
.expect("undefined intrinsics module"),
));

Ok(artifact)
}

/// Compile a single [hir::Module] as a program.
///
/// It is assumed that the given module has been validated, and that all necessary
/// rewrites have been applied. If one of these invariants is not upheld, compilation
/// may fail.
pub fn compile_module(&mut self, input: Box<hir::Module>) -> CompilerResult<Box<Program>> {
assert!(input.entrypoint().is_some(), "cannot compile a program without an entrypoint");

let program =
hir::ProgramBuilder::new(&self.session.diagnostics).with_module(input)?.link()?;

match self.compile(program)? {
MasmArtifact::Executable(program) => Ok(program),
_ => unreachable!("expected compiler to produce an executable, got a library"),
}
}

/// Compile a set of [hir::Module] as a program.
///
/// It is assumed that the given modules have been validated, and that all necessary
/// rewrites have been applied. If one of these invariants is not upheld, compilation
/// may fail.
pub fn compile_modules<I: IntoIterator<Item = Box<hir::Module>>>(
&mut self,
input: I,
) -> CompilerResult<Box<Program>> {
let mut builder = hir::ProgramBuilder::new(&self.session.diagnostics);
for module in input.into_iter() {
builder.add_module(module)?;
}

let program = builder.link()?;

assert!(program.has_entrypoint(), "cannot compile a program without an entrypoint");

match self.compile(program)? {
MasmArtifact::Executable(program) => Ok(program),
_ => unreachable!("expected compiler to produce an executable, got a library"),
}
}
}

pub fn default_rewrites<P>(registered: P, session: &Session) -> RewriteSet<hir::Module>
where
P: IntoIterator<Item = Box<dyn RewritePass<Entity = hir::Module>>>,
<P as IntoIterator>::IntoIter: ExactSizeIterator,
{
use midenc_hir::pass::ModuleRewritePassAdapter;

let registered = registered.into_iter();

// If no rewrites were explicitly enabled, and conversion to Miden Assembly is,
// then we must ensure that the basic transformation passes are applied.
//
// Otherwise, assume that the intent was to skip those rewrites and do not add them
let mut rewrites = RewriteSet::default();
if registered.len() == 0 {
if session.should_codegen() {
let fn_rewrites = default_function_rewrites(session);
for rewrite in fn_rewrites {
rewrites.push(ModuleRewritePassAdapter::new(rewrite));
}
}
} else {
rewrites.extend(registered);
}

rewrites
}

pub fn default_function_rewrites(session: &Session) -> RewriteSet<hir::Function> {
use midenc_hir_transform as transforms;

// If no rewrites were explicitly enabled, and conversion to Miden Assembly is,
// then we must ensure that the basic transformation passes are applied.
//
// Otherwise, assume that the intent was to skip those rewrites and do not add them
let mut rewrites = RewriteSet::default();
if session.should_codegen() {
rewrites.push(transforms::SplitCriticalEdges);
rewrites.push(transforms::Treeify);
rewrites.push(transforms::InlineBlocks);
rewrites.push(transforms::ApplySpills);
}

rewrites
}
Loading

0 comments on commit 0230276

Please sign in to comment.