1
0

Extend VM optimizations

This commit is contained in:
Jeff 2025-02-11 11:09:50 -05:00
parent d53521c0f9
commit 77148cbf3f
4 changed files with 99 additions and 39 deletions

View File

@ -376,7 +376,7 @@ impl<'a, W: Write> Disassembler<'a, W> {
} }
pub fn write_prototype_section(&mut self) -> Result<(), io::Error> { pub fn write_prototype_section(&mut self) -> Result<(), io::Error> {
self.write_center_border_bold("Functions")?; self.write_center_border_bold("Prototypes")?;
for chunk in &self.chunk.prototypes { for chunk in &self.chunk.prototypes {
chunk chunk

View File

@ -2023,6 +2023,7 @@ impl<'src> Compiler<'src> {
let end = self.current_position.1; let end = self.current_position.1;
let destination = match function_return_type { let destination = match function_return_type {
Type::None => 0,
Type::Boolean => self.next_boolean_register(), Type::Boolean => self.next_boolean_register(),
Type::Byte => self.next_byte_register(), Type::Byte => self.next_byte_register(),
Type::Character => self.next_character_register(), Type::Character => self.next_character_register(),

View File

@ -1,7 +1,4 @@
use std::{ use std::fmt::{self, Display, Formatter};
fmt::{self, Display, Formatter},
ptr,
};
use tracing::{Level, span, trace}; use tracing::{Level, span, trace};
@ -34,13 +31,17 @@ impl ActionSequence {
let mut loop_instructions = Vec::new(); let mut loop_instructions = Vec::new();
let mut previous = instruction; let mut previous = instruction;
loop_instructions.push(InstructionFields::from(instruction)); loop_instructions
.push((InstructionFields::from(instruction), PointerCache::new()));
while let Some(instruction) = instructions.next() { while let Some(instruction) = instructions.next() {
loop_instructions.push(InstructionFields::from(instruction)); loop_instructions
.push((InstructionFields::from(instruction), PointerCache::new()));
if instruction.operation() == Operation::LESS if matches!(
&& previous.operation() == Operation::JUMP instruction.operation(),
Operation::EQUAL | Operation::LESS | Operation::LESS_EQUAL
) && previous.operation() == Operation::JUMP
{ {
let Jump { let Jump {
offset: forward_offset, offset: forward_offset,
@ -58,7 +59,7 @@ impl ActionSequence {
loop_instructions.reverse(); loop_instructions.reverse();
let loop_action = Action { let loop_action = Action {
logic: RUNNER_LOGIC_TABLE[0], logic: ACTION_LOGIC_TABLE[0],
instruction: InstructionFields::default(), instruction: InstructionFields::default(),
optimized_logic: Some(optimized_loop), optimized_logic: Some(optimized_loop),
loop_instructions: Some(loop_instructions), loop_instructions: Some(loop_instructions),
@ -79,6 +80,10 @@ impl ActionSequence {
ActionSequence { actions } ActionSequence { actions }
} }
pub fn len(&self) -> usize {
self.actions.len()
}
} }
impl Display for ActionSequence { impl Display for ActionSequence {
@ -97,18 +102,18 @@ impl Display for ActionSequence {
} }
} }
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug)]
pub struct Action { pub struct Action {
pub logic: RunnerLogic, pub logic: ActionLogic,
pub instruction: InstructionFields, pub instruction: InstructionFields,
pub optimized_logic: Option<fn(Vec<InstructionFields>, &mut Thread)>, pub optimized_logic: Option<OptimizedActionLogic>,
pub loop_instructions: Option<Vec<InstructionFields>>, pub loop_instructions: Option<Vec<(InstructionFields, PointerCache)>>,
} }
impl From<&Instruction> for Action { impl From<&Instruction> for Action {
fn from(instruction: &Instruction) -> Self { fn from(instruction: &Instruction) -> Self {
let operation = instruction.operation(); let operation = instruction.operation();
let logic = RUNNER_LOGIC_TABLE[operation.0 as usize]; let logic = ACTION_LOGIC_TABLE[operation.0 as usize];
let instruction = InstructionFields::from(instruction); let instruction = InstructionFields::from(instruction);
Action { Action {
@ -125,7 +130,7 @@ impl Display for Action {
if let Some(loop_instructions) = &self.loop_instructions { if let Some(loop_instructions) = &self.loop_instructions {
write!(f, "LOOP(")?; write!(f, "LOOP(")?;
for (index, instruction) in loop_instructions.iter().enumerate() { for (index, (instruction, _)) in loop_instructions.iter().enumerate() {
write!(f, "{}", instruction.operation)?; write!(f, "{}", instruction.operation)?;
if index < loop_instructions.len() - 1 { if index < loop_instructions.len() - 1 {
@ -140,9 +145,10 @@ impl Display for Action {
} }
} }
pub type RunnerLogic = fn(InstructionFields, &mut Thread); pub type ActionLogic = fn(InstructionFields, &mut Thread);
pub type OptimizedActionLogic = fn(Vec<(InstructionFields, PointerCache)>, &mut Thread);
pub const RUNNER_LOGIC_TABLE: [RunnerLogic; 23] = [ pub const ACTION_LOGIC_TABLE: [ActionLogic; 23] = [
point, point,
close, close,
load_encoded, load_encoded,
@ -1663,16 +1669,14 @@ pub fn r#return(instruction: InstructionFields, thread: &mut Thread) {
} }
} }
fn optimized_loop(instructions: Vec<InstructionFields>, thread: &mut Thread) { fn optimized_loop(instructions: Vec<(InstructionFields, PointerCache)>, thread: &mut Thread) {
let span = span!(Level::TRACE, "Optimized Loop"); let span = span!(Level::TRACE, "Optimized Loop");
let _ = span.enter(); let _ = span.enter();
let mut loop_ip = 0; let mut loop_ip = 0;
let mut add_integer_pointers: [*const i64; 2] = [ptr::null(); 2];
let mut less_integer_pointers: [*const i64; 2] = [ptr::null(); 2];
while loop_ip < instructions.len() { while loop_ip < instructions.len() {
let instruction = instructions[loop_ip]; let (instruction, mut pointer_cache) = instructions[loop_ip];
loop_ip += 1; loop_ip += 1;
@ -1681,7 +1685,7 @@ fn optimized_loop(instructions: Vec<InstructionFields>, thread: &mut Thread) {
trace!("Running loop-optimized ADD instruction"); trace!("Running loop-optimized ADD instruction");
let destination = instruction.a_field as usize; let destination = instruction.a_field as usize;
let sum = if add_integer_pointers[0].is_null() { let sum = if pointer_cache.integers[0].is_null() {
let left = instruction.b_field as usize; let left = instruction.b_field as usize;
let left_is_constant = instruction.b_is_constant; let left_is_constant = instruction.b_is_constant;
let right = instruction.c_field as usize; let right = instruction.c_field as usize;
@ -1706,13 +1710,13 @@ fn optimized_loop(instructions: Vec<InstructionFields>, thread: &mut Thread) {
thread.get_integer_register(right) thread.get_integer_register(right)
}; };
add_integer_pointers[0] = left_value; pointer_cache.integers[0] = left_value;
add_integer_pointers[1] = right_value; pointer_cache.integers[1] = right_value;
left_value.saturating_add(*right_value) left_value.saturating_add(*right_value)
} else { } else {
let left_value = unsafe { *add_integer_pointers[0] }; let left_value = unsafe { *pointer_cache.integers[0] };
let right_value = unsafe { *add_integer_pointers[1] }; let right_value = unsafe { *pointer_cache.integers[1] };
left_value.saturating_add(right_value) left_value.saturating_add(right_value)
}; };
@ -1725,8 +1729,7 @@ fn optimized_loop(instructions: Vec<InstructionFields>, thread: &mut Thread) {
trace!("Running loop-optimized LESS instruction"); trace!("Running loop-optimized LESS instruction");
let comparator = instruction.d_field; let comparator = instruction.d_field;
let result = if pointer_cache.integers[0].is_null() {
let result = if less_integer_pointers[0].is_null() {
let left = instruction.b_field as usize; let left = instruction.b_field as usize;
let left_is_constant = instruction.b_is_constant; let left_is_constant = instruction.b_is_constant;
let right = instruction.c_field as usize; let right = instruction.c_field as usize;
@ -1750,13 +1753,13 @@ fn optimized_loop(instructions: Vec<InstructionFields>, thread: &mut Thread) {
thread.get_integer_register(right) thread.get_integer_register(right)
}; };
less_integer_pointers[0] = left_value; pointer_cache.integers[0] = left_value;
less_integer_pointers[1] = right_value; pointer_cache.integers[1] = right_value;
left_value < right_value left_value < right_value
} else { } else {
let left_value = unsafe { *less_integer_pointers[0] }; let left_value = unsafe { *pointer_cache.integers[0] };
let right_value = unsafe { *less_integer_pointers[1] }; let right_value = unsafe { *pointer_cache.integers[1] };
left_value < right_value left_value < right_value
}; };
@ -1765,8 +1768,51 @@ fn optimized_loop(instructions: Vec<InstructionFields>, thread: &mut Thread) {
loop_ip += 1; loop_ip += 1;
} }
} }
Operation::LESS_EQUAL => {
trace!("Running loop-optimized LESS_EQUAL instruction");
let comparator = instruction.d_field;
let result = if pointer_cache.integers[0].is_null() {
let left = instruction.b_field as usize;
let left_is_constant = instruction.b_is_constant;
let right = instruction.c_field as usize;
let right_is_constant = instruction.c_is_constant;
let left_value = if left_is_constant {
if cfg!(debug_assertions) {
thread.get_constant(left).as_integer().unwrap()
} else {
unsafe { thread.get_constant(left).as_integer().unwrap_unchecked() }
}
} else {
thread.get_integer_register(left)
};
let right_value = if right_is_constant {
if cfg!(debug_assertions) {
thread.get_constant(right).as_integer().unwrap()
} else {
unsafe { thread.get_constant(right).as_integer().unwrap_unchecked() }
}
} else {
thread.get_integer_register(right)
};
pointer_cache.integers[0] = left_value;
pointer_cache.integers[1] = right_value;
left_value <= right_value
} else {
let left_value = unsafe { *pointer_cache.integers[0] };
let right_value = unsafe { *pointer_cache.integers[1] };
left_value <= right_value
};
if result == comparator {
loop_ip += 1;
}
}
Operation::JUMP => { Operation::JUMP => {
trace!("Running JUMP instruction"); trace!("Running loop-optimized JUMP instruction");
let offset = instruction.b_field as usize; let offset = instruction.b_field as usize;
let is_positive = instruction.c_field != 0; let is_positive = instruction.c_field != 0;
@ -1778,13 +1824,26 @@ fn optimized_loop(instructions: Vec<InstructionFields>, thread: &mut Thread) {
} }
} }
_ => { _ => {
let runner = RUNNER_LOGIC_TABLE[instruction.operation.0 as usize]; let runner = ACTION_LOGIC_TABLE[instruction.operation.0 as usize];
runner(instruction, thread); runner(instruction, thread);
} }
} }
} }
} }
#[derive(Debug, Clone, Copy)]
pub struct PointerCache {
integers: [*const i64; 2],
}
impl PointerCache {
fn new() -> Self {
Self {
integers: [std::ptr::null(); 2],
}
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
@ -1792,7 +1851,7 @@ mod tests {
use super::*; use super::*;
const ALL_OPERATIONS: [(Operation, RunnerLogic); 23] = [ const ALL_OPERATIONS: [(Operation, ActionLogic); 23] = [
(Operation::POINT, point), (Operation::POINT, point),
(Operation::CLOSE, close), (Operation::CLOSE, close),
(Operation::LOAD_ENCODED, load_encoded), (Operation::LOAD_ENCODED, load_encoded),
@ -1821,7 +1880,7 @@ mod tests {
#[test] #[test]
fn operations_map_to_the_correct_runner() { fn operations_map_to_the_correct_runner() {
for (operation, expected_runner) in ALL_OPERATIONS { for (operation, expected_runner) in ALL_OPERATIONS {
let actual_runner = RUNNER_LOGIC_TABLE[operation.0 as usize]; let actual_runner = ACTION_LOGIC_TABLE[operation.0 as usize];
assert_eq!( assert_eq!(
expected_runner, actual_runner, expected_runner, actual_runner,

View File

@ -54,8 +54,6 @@ impl Thread {
unsafe { current_frame.action_sequence.actions.get_unchecked_mut(ip) } unsafe { current_frame.action_sequence.actions.get_unchecked_mut(ip) }
}; };
trace!("Instruction: {}", current_action.instruction.operation);
if let (Some(optimized_logic), Some(loop_instructions)) = ( if let (Some(optimized_logic), Some(loop_instructions)) = (
&current_action.optimized_logic, &current_action.optimized_logic,
&current_action.loop_instructions, &current_action.loop_instructions,
@ -64,6 +62,8 @@ impl Thread {
(optimized_logic)(loop_instructions, &mut self); (optimized_logic)(loop_instructions, &mut self);
} else { } else {
trace!("Instruction: {}", current_action.instruction.operation);
(current_action.logic)(current_action.instruction, &mut self); (current_action.logic)(current_action.instruction, &mut self);
} }