use super::{
BytecodeBlock, BytecodeBlockId, BytecodeEdge, BytecodeEdgeKind, BytecodeImmediate,
BytecodeImmediateId, BytecodeInstruction, BytecodeInstructionId, BytecodeInstructionStream,
BytecodeOperand, BytecodePhi, BytecodePhiId, BytecodeProjection, BytecodeProjectionId,
InstructionPc,
};
use crate::error::BytecodeReadError;
use crate::model::Register;
use crate::model::{Instruction, InstructionAux};
use crate::opcodes::Opcode;
use std::collections::{HashMap, HashSet};
fn constant_index(value: u32) -> i32 {
i32::try_from(value).expect("constant index must fit int32")
}
pub(super) struct FunctionGraphBuilder {
pub(super) immediates: Vec<BytecodeImmediate>,
pub(super) phis: Vec<BytecodePhi>,
pub(super) projections: Vec<BytecodeProjection>,
pub(super) registers: HashMap<BytecodeOperand, Register>,
pub(super) block_phis: Vec<Vec<BytecodePhiId>>,
producers: Producers,
current_block: BytecodeBlockId,
}
impl Default for FunctionGraphBuilder {
fn default() -> Self {
Self {
immediates: Vec::new(),
phis: Vec::new(),
projections: Vec::new(),
registers: HashMap::new(),
block_phis: Vec::new(),
producers: Producers::default(),
current_block: BytecodeBlockId::new(0),
}
}
}
#[derive(Clone)]
struct BlockProducers {
own: HashMap<Register, BytecodeOperand>,
cached: HashMap<Register, BytecodeOperand>,
multi_return: Option<BytecodeOperand>,
multi_return_start: Register,
invalid_after: i32,
sealed: bool,
unsealed_predecessors: usize,
incomplete_phis: HashMap<Register, BytecodeOperand>,
}
impl Default for BlockProducers {
fn default() -> Self {
Self {
own: HashMap::new(),
cached: HashMap::new(),
multi_return: None,
multi_return_start: 0xff,
invalid_after: 255,
sealed: false,
unsealed_predecessors: 0,
incomplete_phis: HashMap::new(),
}
}
}
#[derive(Default)]
struct Producers {
blocks: Vec<BlockProducers>,
}
impl FunctionGraphBuilder {
pub(super) fn new(
blocks: &[BytecodeBlock],
parameter_count: u8,
entry: BytecodeBlockId,
) -> Self {
let mut builder = Self {
producers: Producers {
blocks: vec![BlockProducers::default(); blocks.len()],
},
block_phis: vec![Vec::new(); blocks.len()],
..Self::default()
};
for (index, block) in blocks.iter().enumerate() {
builder.producers.blocks[index].unsealed_predecessors = block.predecessors().len();
builder.producers.blocks[index].sealed = block.predecessors().is_empty();
}
for register in 0..parameter_count {
builder.add_producer_to(entry, register, BytecodeOperand::VmRegister(register));
}
builder
}
pub(super) fn begin_block(
&mut self,
block: BytecodeBlockId,
_entry: BytecodeBlockId,
_predecessors: &[BytecodeEdge],
) {
self.current_block = block;
}
}
mod operands;
mod producers;