use super::{FinalProgram, FnName, SelectorOpt};
use crate::{
asm_generation::{
fuel::{
allocated_abstract_instruction_set::AllocatedAbstractInstructionSet,
data_section::DataSection,
},
ProgramKind,
},
asm_lang::{allocated_ops::AllocatedInstruction, Label},
decl_engine::DeclRefFunction,
};
use either::Either;
pub(crate) struct AllocatedProgram {
pub(crate) kind: ProgramKind,
pub(crate) data_section: DataSection,
pub(crate) prologue: AllocatedAbstractInstructionSet,
pub(crate) functions: Vec<AllocatedAbstractInstructionSet>,
pub(crate) entries: Vec<(SelectorOpt, Label, FnName, Option<DeclRefFunction>)>,
}
impl AllocatedProgram {
pub(crate) fn into_final_program(mut self) -> Result<FinalProgram, crate::CompileError> {
let abstract_ops = AllocatedAbstractInstructionSet {
function: None,
ops: std::iter::once(self.prologue.ops)
.chain(self.functions.into_iter().map(|f| f.ops))
.flatten()
.collect(),
};
let num_non_copy_loads = abstract_ops
.ops
.iter()
.filter(|op| match &op.opcode {
Either::Left(AllocatedInstruction::LoadDataId(_, data_id)) => !self
.data_section
.has_copy_type(data_id)
.expect("`LoadDataId` refers to a non-existent data section entry"),
_ => false,
})
.count();
self.data_section.reserve_pointer_slots(num_non_copy_loads);
let (far_jump_sizes, worst_case_far_jump_words) = abstract_ops.collect_far_jumps();
self.data_section
.freeze_configurables_base_offset(8 * worst_case_far_jump_words);
let (realized_ops, mut label_offsets) =
abstract_ops.lower_to_realized_ops(&mut self.data_section, &far_jump_sizes)?;
let ops = realized_ops.lower_to_allocated_ops();
let entries = self
.entries
.into_iter()
.map(|(selector, label, name, test_decl_ref)| {
let offset = label_offsets
.remove(&label)
.expect("no offset for entry")
.offs;
(selector, offset, name, test_decl_ref)
})
.collect();
Ok(FinalProgram {
kind: self.kind,
data_section: self.data_section,
ops,
entries,
})
}
}
impl std::fmt::Display for AllocatedProgram {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(f, ";; Program kind: {:?}", self.kind)?;
writeln!(f, ";; --- Prologue ---\n{}\n", self.prologue)?;
writeln!(f, ";; --- Functions ---")?;
for function in &self.functions {
writeln!(f, "{function}\n")?;
}
writeln!(f, ";; --- Data ---")?;
writeln!(f, "{}", self.data_section)
}
}