Extend VM optimizations
This commit is contained in:
parent
d53521c0f9
commit
77148cbf3f
@ -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
|
||||||
|
@ -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(),
|
||||||
|
@ -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,
|
||||||
|
@ -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)) = (
|
||||||
¤t_action.optimized_logic,
|
¤t_action.optimized_logic,
|
||||||
¤t_action.loop_instructions,
|
¤t_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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user