From 6f0955c29a8dcdd1913cd10bace7c0e73d310645 Mon Sep 17 00:00:00 2001 From: Jeff Date: Thu, 6 Feb 2025 12:42:55 -0500 Subject: [PATCH] Improve control flow register consolidation --- dust-lang/src/chunk/mod.rs | 36 ++----- dust-lang/src/compiler/mod.rs | 86 +++++++++------- dust-lang/src/compiler/optimize.rs | 64 ------------ dust-lang/src/instruction/add.rs | 4 +- dust-lang/src/instruction/call.rs | 4 +- dust-lang/src/instruction/call_native.rs | 4 +- dust-lang/src/instruction/close.rs | 4 +- dust-lang/src/instruction/divide.rs | 4 +- dust-lang/src/instruction/equal.rs | 4 +- dust-lang/src/instruction/jump.rs | 4 +- dust-lang/src/instruction/less.rs | 4 +- dust-lang/src/instruction/less_equal.rs | 4 +- dust-lang/src/instruction/load_boolean.rs | 4 +- dust-lang/src/instruction/load_constant.rs | 21 +++- dust-lang/src/instruction/load_function.rs | 4 +- dust-lang/src/instruction/load_list.rs | 4 +- dust-lang/src/instruction/load_self.rs | 4 +- dust-lang/src/instruction/mod.rs | 32 ++++-- dust-lang/src/instruction/modulo.rs | 4 +- dust-lang/src/instruction/multiply.rs | 4 +- dust-lang/src/instruction/negate.rs | 4 +- dust-lang/src/instruction/not.rs | 4 +- dust-lang/src/instruction/point.rs | 4 +- dust-lang/src/instruction/return.rs | 4 +- dust-lang/src/instruction/subtract.rs | 4 +- dust-lang/src/instruction/test.rs | 4 +- dust-lang/src/instruction/test_set.rs | 4 +- dust-lang/src/value/concrete_value.rs | 66 +++++++++++- dust-lang/src/vm/action.rs | 111 ++++++++++++++------- dust-lang/src/vm/thread.rs | 4 +- 30 files changed, 281 insertions(+), 227 deletions(-) delete mode 100644 dust-lang/src/compiler/optimize.rs diff --git a/dust-lang/src/chunk/mod.rs b/dust-lang/src/chunk/mod.rs index 2944767..3f5e215 100644 --- a/dust-lang/src/chunk/mod.rs +++ b/dust-lang/src/chunk/mod.rs @@ -27,7 +27,7 @@ use std::sync::Arc; use serde::{Deserialize, Serialize}; -use crate::{DustString, Function, FunctionType, Instruction, Span, Value}; +use crate::{ConcreteValue, DustString, Function, FunctionType, Instruction, Span, Value}; /// Representation of a Dust program or function. /// @@ -39,38 +39,22 @@ pub struct Chunk { pub(crate) instructions: Vec, pub(crate) positions: Vec, - pub(crate) constants: Vec, + pub(crate) constants: Vec, pub(crate) locals: Vec, pub(crate) prototypes: Vec>, - pub(crate) register_count: usize, + pub(crate) boolean_register_count: usize, + pub(crate) byte_register_count: usize, + pub(crate) character_register_count: usize, + pub(crate) float_register_count: usize, + pub(crate) integer_register_count: usize, + pub(crate) string_register_count: usize, + pub(crate) list_register_count: usize, + pub(crate) function_register_count: usize, pub(crate) prototype_index: u16, } impl Chunk { - #[cfg(any(test, debug_assertions))] - pub fn with_data( - name: Option, - r#type: FunctionType, - instructions: impl Into>, - positions: impl Into>, - constants: impl Into>, - locals: impl Into>, - prototypes: impl IntoIterator, - ) -> Self { - Self { - name, - r#type, - instructions: instructions.into(), - positions: positions.into(), - constants: constants.into(), - locals: locals.into(), - prototypes: prototypes.into_iter().map(Arc::new).collect(), - register_count: 0, - prototype_index: 0, - } - } - pub fn as_function(&self) -> Function { Function { name: self.name.clone(), diff --git a/dust-lang/src/compiler/mod.rs b/dust-lang/src/compiler/mod.rs index c5c5ca2..d5e99a6 100644 --- a/dust-lang/src/compiler/mod.rs +++ b/dust-lang/src/compiler/mod.rs @@ -19,7 +19,6 @@ //! pass that chunk to the VM. Otherwise, if the compiler gives no errors and the VM encounters a //! runtime error, it is the compiler's fault and the error should be fixed here. mod error; -mod optimize; mod parse_rule; mod type_checks; @@ -30,12 +29,10 @@ use type_checks::{check_math_type, check_math_types}; use std::{mem::replace, sync::Arc}; -use optimize::control_flow_register_consolidation; - use crate::{ Chunk, ConcreteValue, DustError, DustString, FunctionType, Instruction, Lexer, Local, - NativeFunction, Operand, Operation, Scope, Span, Token, TokenKind, Type, Value, - instruction::{CallNative, Close, Jump, LoadList, Point, Return, TypeCode}, + NativeFunction, Operand, Operation, Scope, Span, Token, TokenKind, Type, + instruction::{CallNative, Jump, LoadList, Point, Return, TypeCode}, }; /// Compiles the input and returns a chunk. @@ -88,7 +85,7 @@ pub struct Compiler<'src> { /// Constants that have been compiled. These are assigned to the chunk when [`Compiler::finish`] /// is called. - constants: Vec, + constants: Vec, /// Block-local variables and their types. The locals are assigned to the chunk when /// [`Compiler::finish`] is called. The types are discarded after compilation. @@ -98,10 +95,6 @@ pub struct Compiler<'src> { /// [`Compiler::finish`] is called. prototypes: Vec>, - /// Maximum stack size required by the chunk. This is assigned to the chunk when - /// [`Compiler::finish`] is called. - stack_size: usize, - /// The first boolean register index that the compiler should use. This is used to avoid reusing /// the registers that are used for the function's arguments. minimum_boolean_register: u16, @@ -175,7 +168,6 @@ impl<'src> Compiler<'src> { constants: Vec::new(), locals: Vec::new(), prototypes: Vec::new(), - stack_size: 0, lexer, minimum_byte_register: 0, minimum_boolean_register: 0, @@ -234,6 +226,14 @@ impl<'src> Compiler<'src> { /// will allow [`Compiler::function_name`] to be both the name used for recursive calls and the /// name of the function when it is compiled. The name can later be seen in the VM's call stack. pub fn finish(self) -> Chunk { + let boolean_register_count = self.next_boolean_register() as usize; + let byte_register_count = self.next_byte_register() as usize; + let character_register_count = self.next_character_register() as usize; + let float_register_count = self.next_float_register() as usize; + let integer_register_count = self.next_integer_register() as usize; + let string_register_count = self.next_string_register() as usize; + let list_register_count = self.next_list_register() as usize; + let function_register_count = self.next_function_register() as usize; let (instructions, positions): (Vec, Vec) = self .instructions .into_iter() @@ -253,7 +253,14 @@ impl<'src> Compiler<'src> { constants: self.constants, locals, prototypes: self.prototypes, - register_count: self.stack_size, + boolean_register_count, + byte_register_count, + character_register_count, + float_register_count, + integer_register_count, + string_register_count, + list_register_count, + function_register_count, prototype_index: self.prototype_index, } } @@ -411,12 +418,11 @@ impl<'src> Compiler<'src> { .rev() .find_map(|(index, (local, _))| { let constant = self.constants.get(local.identifier_index as usize)?; - let identifier = - if let Value::Concrete(ConcreteValue::String(identifier)) = constant { - identifier - } else { - return None; - }; + let identifier = if let ConcreteValue::String(identifier) = constant { + identifier + } else { + return None; + }; if identifier == identifier_text { Some(index as u16) @@ -440,7 +446,7 @@ impl<'src> Compiler<'src> { ) -> (u16, u16) { info!("Declaring local {identifier}"); - let identifier = Value::Concrete(ConcreteValue::string(identifier)); + let identifier = ConcreteValue::string(identifier); let identifier_index = self.push_or_get_constant(identifier); let local_index = self.locals.len() as u16; @@ -462,7 +468,7 @@ impl<'src> Compiler<'src> { }) } - fn push_or_get_constant(&mut self, value: Value) -> u16 { + fn push_or_get_constant(&mut self, value: ConcreteValue) -> u16 { if let Some(index) = self .constants .iter() @@ -592,12 +598,6 @@ impl<'src> Compiler<'src> { position.to_string() ); - if instruction.yields_value() { - let destination = instruction.a_field() as usize; - - self.stack_size = (destination + 1).max(self.stack_size); - } - self.instructions.push((instruction, r#type, position)); } @@ -607,7 +607,7 @@ impl<'src> Compiler<'src> { position: Span, ) -> Result<(), CompileError> { let r#type = constant.r#type(); - let constant_index = self.push_or_get_constant(Value::Concrete(constant)); + let constant_index = self.push_or_get_constant(constant); let destination = match r#type { Type::Character => self.next_character_register(), Type::Float => self.next_float_register(), @@ -615,7 +615,8 @@ impl<'src> Compiler<'src> { Type::String => self.next_string_register(), _ => todo!(), }; - let load_constant = Instruction::load_constant(destination, constant_index, false); + let load_constant = + Instruction::load_constant(destination, constant_index, r#type.type_code(), false); self.emit_instruction(load_constant, r#type, position); @@ -1420,7 +1421,7 @@ impl<'src> Compiler<'src> { } let if_block_end = self.instructions.len(); - let mut if_block_distance = (if_block_end - if_block_start) as u16; + let mut if_block_distance = if_block_end - if_block_start; let if_block_type = self.get_last_instruction_type(); if let Token::Else = self.current_token { @@ -1442,7 +1443,7 @@ impl<'src> Compiler<'src> { } let else_block_end = self.instructions.len(); - let else_block_distance = (else_block_end - if_block_end) as u16; + let else_block_distance = else_block_end - if_block_end; let else_block_type = self.get_last_instruction_type(); if let Err(conflict) = if_block_type.check(&else_block_type) { @@ -1455,16 +1456,17 @@ impl<'src> Compiler<'src> { match else_block_distance { 0 => {} 1 => { - if let Some(Operation::LOAD_BOOLEAN | Operation::LOAD_CONSTANT) = - self.get_last_operation() + if let Some([Operation::LOAD_BOOLEAN | Operation::LOAD_CONSTANT, _]) = + self.get_last_operations() { - let (loader, _, _) = self.instructions.last_mut().unwrap(); + let loader_index = self.instructions.len() - 2; + let (loader, _, _) = self.instructions.get_mut(loader_index).unwrap(); loader.set_c_field(true as u16); } else { if_block_distance += 1; let jump = Instruction::from(Jump { - offset: else_block_distance, + offset: else_block_distance as u16, is_positive: true, }); @@ -1475,7 +1477,7 @@ impl<'src> Compiler<'src> { 2.. => { if_block_distance += 1; let jump = Instruction::from(Jump { - offset: else_block_distance, + offset: else_block_distance as u16, is_positive: true, }); @@ -1484,11 +1486,21 @@ impl<'src> Compiler<'src> { } } - let jump = Instruction::jump(if_block_distance, true); + let jump = Instruction::jump(if_block_distance as u16, true); self.instructions .insert(if_block_start, (jump, Type::None, if_block_start_position)); - control_flow_register_consolidation(self); + + let if_block_last_instruction_index = self.instructions.len() - else_block_distance - 1; + let else_block_last_instruction_index = self.instructions.len() - 1; + + let if_block_last_instruction = self.instructions[if_block_last_instruction_index].0; + let else_block_last_instruction = + &mut self.instructions[else_block_last_instruction_index].0; + + else_block_last_instruction.set_a_field(if_block_last_instruction.a_field()); + + println!("{if_block_last_instruction_index} {else_block_last_instruction_index}"); Ok(()) } diff --git a/dust-lang/src/compiler/optimize.rs b/dust-lang/src/compiler/optimize.rs deleted file mode 100644 index bf22d34..0000000 --- a/dust-lang/src/compiler/optimize.rs +++ /dev/null @@ -1,64 +0,0 @@ -//! Functions used by the compiler to optimize a chunk's bytecode during compilation. - -use tracing::debug; - -use crate::{Compiler, Instruction, Operation}; - -/// Optimizes a control flow pattern to use fewer registers and avoid using a `POINT` instruction. -/// Use this after parsing an if/else statement. -/// -/// This makes the following examples compile to the same bytecode: -/// -/// ```dust -/// 4 == 4 -/// ``` -/// -/// ```dust -/// if 4 == 4 { true } else { false } -/// ``` -/// -/// When they occur in the sequence shown below, instructions can be optimized by taking advantage -/// of the loaders' ability to skip an instruction after loading a value. If these instructions are -/// the result of a binary expression, this will not change anything because they were already -/// emitted optimally. Control flow patterns, however, can be optimized because the load -/// instructions are from seperate expressions that each uses its own register. Since only one of -/// the two branches will be executed, this is wasteful. It would also require the compiler to emit -/// a `POINT` instruction to prevent the VM from encountering an empty register. -/// -/// The instructions must be in the following order: -/// - `TEST` or any of the `EQUAL`, `LESS` or `LESS_EQUAL` instructions -/// - `JUMP` -/// - `LOAD_BOOLEAN` or `LOAD_CONSTANT` -/// - `LOAD_BOOLEAN` or `LOAD_CONSTANT` -/// -/// This optimization was taken from `A No-Frills Introduction to Lua 5.1 VM Instructions` by -/// Kein-Hong Man. -pub fn control_flow_register_consolidation(compiler: &mut Compiler) { - if !matches!( - compiler.get_last_operations(), - Some([ - Operation::TEST | Operation::EQUAL | Operation::LESS | Operation::LESS_EQUAL, - Operation::JUMP, - Operation::LOAD_BOOLEAN | Operation::LOAD_CONSTANT, - Operation::LOAD_BOOLEAN | Operation::LOAD_CONSTANT, - ]) - ) { - return; - } - - debug!("Consolidating registers for control flow optimization"); - - let first_loader_index = compiler.instructions.len() - 2; - let (first_loader, _, _) = &mut compiler.instructions.get_mut(first_loader_index).unwrap(); - let first_loader_destination = first_loader.a_field(); - *first_loader = - Instruction::load_boolean(first_loader.a_field(), first_loader.b_field() != 0, true); - - let second_loader_index = compiler.instructions.len() - 1; - let (second_loader, _, _) = &mut compiler.instructions.get_mut(second_loader_index).unwrap(); - *second_loader = Instruction::load_boolean( - first_loader_destination, - second_loader.b_field() != 0, - false, - ); -} diff --git a/dust-lang/src/instruction/add.rs b/dust-lang/src/instruction/add.rs index 956a732..be81cc5 100644 --- a/dust-lang/src/instruction/add.rs +++ b/dust-lang/src/instruction/add.rs @@ -1,6 +1,6 @@ use std::fmt::{self, Display, Formatter}; -use super::{Instruction, InstructionBuilder, Operand, Operation, TypeCode}; +use super::{Instruction, InstructionFields, Operand, Operation, TypeCode}; pub struct Add { pub destination: u16, @@ -36,7 +36,7 @@ impl From for Instruction { let b_type = add.left_type; let c_type = add.right_type; - InstructionBuilder { + InstructionFields { operation, a_field, b_field, diff --git a/dust-lang/src/instruction/call.rs b/dust-lang/src/instruction/call.rs index ff69533..cbbf5a1 100644 --- a/dust-lang/src/instruction/call.rs +++ b/dust-lang/src/instruction/call.rs @@ -2,7 +2,7 @@ use std::fmt::{self, Display, Formatter}; use crate::{Instruction, Operation}; -use super::InstructionBuilder; +use super::InstructionFields; pub struct Call { pub destination: u16, @@ -34,7 +34,7 @@ impl From for Instruction { let c_field = call.argument_count; let d_field = call.is_recursive; - InstructionBuilder { + InstructionFields { operation: Operation::CALL, a_field, b_field, diff --git a/dust-lang/src/instruction/call_native.rs b/dust-lang/src/instruction/call_native.rs index f66fac4..cb3a2b4 100644 --- a/dust-lang/src/instruction/call_native.rs +++ b/dust-lang/src/instruction/call_native.rs @@ -2,7 +2,7 @@ use std::fmt::Display; use crate::{Instruction, NativeFunction, Operation}; -use super::InstructionBuilder; +use super::InstructionFields; pub struct CallNative { pub destination: u16, @@ -30,7 +30,7 @@ impl From for Instruction { let b_field = call_native.function as u16; let c_field = call_native.argument_count; - InstructionBuilder { + InstructionFields { operation, a_field, b_field, diff --git a/dust-lang/src/instruction/close.rs b/dust-lang/src/instruction/close.rs index 9174438..ac5bc77 100644 --- a/dust-lang/src/instruction/close.rs +++ b/dust-lang/src/instruction/close.rs @@ -2,7 +2,7 @@ use std::fmt::{self, Display, Formatter}; use crate::{Instruction, Operation}; -use super::InstructionBuilder; +use super::InstructionFields; pub struct Close { pub from: u16, @@ -24,7 +24,7 @@ impl From for Instruction { let b_field = close.from; let c_field = close.to; - InstructionBuilder { + InstructionFields { operation, b_field, c_field, diff --git a/dust-lang/src/instruction/divide.rs b/dust-lang/src/instruction/divide.rs index 2e20c21..8e3fc62 100644 --- a/dust-lang/src/instruction/divide.rs +++ b/dust-lang/src/instruction/divide.rs @@ -1,6 +1,6 @@ use std::fmt::{self, Display, Formatter}; -use super::{Instruction, InstructionBuilder, Operand, Operation, TypeCode}; +use super::{Instruction, InstructionFields, Operand, Operation, TypeCode}; pub struct Divide { pub destination: u16, @@ -36,7 +36,7 @@ impl From for Instruction { let b_type = divide.left_type; let c_type = divide.right_type; - InstructionBuilder { + InstructionFields { operation, a_field, b_field, diff --git a/dust-lang/src/instruction/equal.rs b/dust-lang/src/instruction/equal.rs index ef099a4..987d8db 100644 --- a/dust-lang/src/instruction/equal.rs +++ b/dust-lang/src/instruction/equal.rs @@ -1,6 +1,6 @@ use std::fmt::{self, Display, Formatter}; -use super::{Instruction, InstructionBuilder, Operand, Operation, TypeCode}; +use super::{Instruction, InstructionFields, Operand, Operation, TypeCode}; pub struct Equal { pub comparator: bool, @@ -36,7 +36,7 @@ impl From for Instruction { let b_type = equal_bool.left_type; let c_type = equal_bool.right_type; - InstructionBuilder { + InstructionFields { operation, b_field, c_field, diff --git a/dust-lang/src/instruction/jump.rs b/dust-lang/src/instruction/jump.rs index 23b82ce..5d1db7b 100644 --- a/dust-lang/src/instruction/jump.rs +++ b/dust-lang/src/instruction/jump.rs @@ -2,7 +2,7 @@ use std::fmt::{self, Display, Formatter}; use crate::{Instruction, Operation}; -use super::InstructionBuilder; +use super::InstructionFields; pub struct Jump { pub offset: u16, @@ -24,7 +24,7 @@ impl From for Instruction { let b_field = jump.offset; let c_field = jump.is_positive as u16; - InstructionBuilder { + InstructionFields { operation, b_field, c_field, diff --git a/dust-lang/src/instruction/less.rs b/dust-lang/src/instruction/less.rs index 025b204..43908b8 100644 --- a/dust-lang/src/instruction/less.rs +++ b/dust-lang/src/instruction/less.rs @@ -1,6 +1,6 @@ use std::fmt::{self, Display, Formatter}; -use super::{Instruction, InstructionBuilder, Operand, Operation, TypeCode}; +use super::{Instruction, InstructionFields, Operand, Operation, TypeCode}; pub struct Less { pub comparator: bool, @@ -36,7 +36,7 @@ impl From for Instruction { let b_type = less.left_type; let c_type = less.right_type; - InstructionBuilder { + InstructionFields { operation, b_field, c_field, diff --git a/dust-lang/src/instruction/less_equal.rs b/dust-lang/src/instruction/less_equal.rs index d1dbf1a..f9c0764 100644 --- a/dust-lang/src/instruction/less_equal.rs +++ b/dust-lang/src/instruction/less_equal.rs @@ -1,6 +1,6 @@ use std::fmt::{self, Display, Formatter}; -use super::{Instruction, InstructionBuilder, Operand, Operation, TypeCode}; +use super::{Instruction, InstructionFields, Operand, Operation, TypeCode}; pub struct LessEqual { pub comparator: bool, @@ -36,7 +36,7 @@ impl From for Instruction { let b_type = less_equal_byte.left_type; let c_type = less_equal_byte.right_type; - InstructionBuilder { + InstructionFields { operation, b_field, c_field, diff --git a/dust-lang/src/instruction/load_boolean.rs b/dust-lang/src/instruction/load_boolean.rs index f14ff3c..4633de8 100644 --- a/dust-lang/src/instruction/load_boolean.rs +++ b/dust-lang/src/instruction/load_boolean.rs @@ -2,7 +2,7 @@ use std::fmt::{self, Display, Formatter}; use crate::{Instruction, Operation}; -use super::InstructionBuilder; +use super::InstructionFields; pub struct LoadBoolean { pub destination: u16, @@ -27,7 +27,7 @@ impl From for Instruction { let b_field = load_boolean.value as u16; let c_field = load_boolean.jump_next as u16; - InstructionBuilder { + InstructionFields { operation, a_field, b_field, diff --git a/dust-lang/src/instruction/load_constant.rs b/dust-lang/src/instruction/load_constant.rs index f26b4c2..b4132b3 100644 --- a/dust-lang/src/instruction/load_constant.rs +++ b/dust-lang/src/instruction/load_constant.rs @@ -2,11 +2,12 @@ use std::fmt::{self, Display, Formatter}; use crate::{Instruction, Operation}; -use super::InstructionBuilder; +use super::{InstructionFields, TypeCode}; pub struct LoadConstant { pub destination: u16, pub constant_index: u16, + pub constant_type: TypeCode, pub jump_next: bool, } @@ -14,11 +15,13 @@ impl From for LoadConstant { fn from(instruction: Instruction) -> Self { let destination = instruction.a_field(); let constant_index = instruction.b_field(); + let constant_type = instruction.b_type(); let jump_next = instruction.c_field() != 0; LoadConstant { destination, constant_index, + constant_type, jump_next, } } @@ -26,10 +29,11 @@ impl From for LoadConstant { impl From for Instruction { fn from(load_constant: LoadConstant) -> Self { - InstructionBuilder { + InstructionFields { operation: Operation::LOAD_CONSTANT, a_field: load_constant.destination, b_field: load_constant.constant_index, + b_type: load_constant.constant_type, c_field: load_constant.jump_next as u16, ..Default::default() } @@ -42,10 +46,21 @@ impl Display for LoadConstant { let LoadConstant { destination, constant_index, + constant_type, jump_next, } = self; - write!(f, "R{destination} = C{constant_index}")?; + match *constant_type { + TypeCode::BOOLEAN => write!(f, "R_BOOL_{destination}")?, + TypeCode::BYTE => write!(f, "R_BYTE_{destination}")?, + TypeCode::CHARACTER => write!(f, "R_CHAR_{destination}")?, + TypeCode::FLOAT => write!(f, "R_FLOAT_{destination}")?, + TypeCode::INTEGER => write!(f, "R_INT_{destination}")?, + TypeCode::STRING => write!(f, "R_STR_{destination}")?, + unsupported => panic!("Unsupported type code: {}", unsupported.0), + } + + write!(f, " = C{constant_index}")?; if *jump_next { write!(f, " JUMP +1")?; diff --git a/dust-lang/src/instruction/load_function.rs b/dust-lang/src/instruction/load_function.rs index 1692e02..f0a3252 100644 --- a/dust-lang/src/instruction/load_function.rs +++ b/dust-lang/src/instruction/load_function.rs @@ -1,6 +1,6 @@ use std::fmt::{self, Display, Formatter}; -use super::{Instruction, InstructionBuilder, Operation}; +use super::{Instruction, InstructionFields, Operation}; pub struct LoadFunction { pub destination: u16, @@ -24,7 +24,7 @@ impl From for LoadFunction { impl From for Instruction { fn from(load_function: LoadFunction) -> Self { - InstructionBuilder { + InstructionFields { operation: Operation::LOAD_FUNCTION, a_field: load_function.destination, b_field: load_function.prototype_index, diff --git a/dust-lang/src/instruction/load_list.rs b/dust-lang/src/instruction/load_list.rs index d891ec5..fd5c3f0 100644 --- a/dust-lang/src/instruction/load_list.rs +++ b/dust-lang/src/instruction/load_list.rs @@ -2,7 +2,7 @@ use std::fmt::{self, Display, Formatter}; use crate::{Instruction, Operation}; -use super::InstructionBuilder; +use super::InstructionFields; pub struct LoadList { pub destination: u16, @@ -26,7 +26,7 @@ impl From for LoadList { impl From for Instruction { fn from(load_list: LoadList) -> Self { - InstructionBuilder { + InstructionFields { operation: Operation::LOAD_LIST, a_field: load_list.destination, b_field: load_list.start_register, diff --git a/dust-lang/src/instruction/load_self.rs b/dust-lang/src/instruction/load_self.rs index 1cb10e2..260430f 100644 --- a/dust-lang/src/instruction/load_self.rs +++ b/dust-lang/src/instruction/load_self.rs @@ -2,7 +2,7 @@ use std::fmt::{self, Display, Formatter}; use crate::{Instruction, Operation}; -use super::InstructionBuilder; +use super::InstructionFields; pub struct LoadSelf { pub destination: u16, @@ -23,7 +23,7 @@ impl From for LoadSelf { impl From for Instruction { fn from(load_self: LoadSelf) -> Self { - InstructionBuilder { + InstructionFields { operation: Operation::LOAD_SELF, a_field: load_self.destination, c_field: load_self.jump_next as u16, diff --git a/dust-lang/src/instruction/mod.rs b/dust-lang/src/instruction/mod.rs index e708cab..c5dcc27 100644 --- a/dust-lang/src/instruction/mod.rs +++ b/dust-lang/src/instruction/mod.rs @@ -151,7 +151,7 @@ pub use type_code::TypeCode; use crate::NativeFunction; #[derive(Clone, Copy, Debug, PartialEq)] -pub struct InstructionBuilder { +pub struct InstructionFields { pub operation: Operation, pub a_field: u16, pub b_field: u16, @@ -163,7 +163,7 @@ pub struct InstructionBuilder { pub c_type: TypeCode, } -impl InstructionBuilder { +impl InstructionFields { pub fn build(self) -> Instruction { let bits = ((self.operation.0 as u64) << 57) | ((self.b_is_constant as u64) << 56) @@ -179,9 +179,9 @@ impl InstructionBuilder { } } -impl From<&Instruction> for InstructionBuilder { +impl From<&Instruction> for InstructionFields { fn from(instruction: &Instruction) -> Self { - InstructionBuilder { + InstructionFields { operation: instruction.operation(), a_field: instruction.a_field(), b_field: instruction.b_field(), @@ -195,9 +195,9 @@ impl From<&Instruction> for InstructionBuilder { } } -impl Default for InstructionBuilder { +impl Default for InstructionFields { fn default() -> Self { - InstructionBuilder { + InstructionFields { operation: Operation::POINT, a_field: 0, b_field: 0, @@ -261,15 +261,21 @@ impl Instruction { } pub fn set_a_field(&mut self, bits: u16) { - self.0 = (bits as u64) << 31; + let mut fields = InstructionFields::from(&*self); + fields.a_field = bits; + *self = fields.build(); } pub fn set_b_field(&mut self, bits: u16) { - self.0 = (bits as u64) << 47; + let mut fields = InstructionFields::from(&*self); + fields.b_field = bits; + *self = fields.build(); } pub fn set_c_field(&mut self, bits: u16) { - self.0 = (bits as u64) << 63; + let mut fields = InstructionFields::from(&*self); + fields.c_field = bits; + *self = fields.build(); } pub fn point(destination: u16, to: Operand) -> Instruction { @@ -288,10 +294,16 @@ impl Instruction { }) } - pub fn load_constant(destination: u16, constant_index: u16, jump_next: bool) -> Instruction { + pub fn load_constant( + destination: u16, + constant_index: u16, + constant_type: TypeCode, + jump_next: bool, + ) -> Instruction { Instruction::from(LoadConstant { destination, constant_index, + constant_type, jump_next, }) } diff --git a/dust-lang/src/instruction/modulo.rs b/dust-lang/src/instruction/modulo.rs index 0f563fc..5aa4fb6 100644 --- a/dust-lang/src/instruction/modulo.rs +++ b/dust-lang/src/instruction/modulo.rs @@ -1,6 +1,6 @@ use std::fmt::{self, Display, Formatter}; -use super::{Instruction, InstructionBuilder, Operand, Operation, TypeCode}; +use super::{Instruction, InstructionFields, Operand, Operation, TypeCode}; pub struct Modulo { pub destination: u16, @@ -36,7 +36,7 @@ impl From for Instruction { let b_type = modulo.left_type; let c_type = modulo.right_type; - InstructionBuilder { + InstructionFields { operation, a_field, b_field, diff --git a/dust-lang/src/instruction/multiply.rs b/dust-lang/src/instruction/multiply.rs index eef813c..76b1e7c 100644 --- a/dust-lang/src/instruction/multiply.rs +++ b/dust-lang/src/instruction/multiply.rs @@ -1,6 +1,6 @@ use std::fmt::{self, Display, Formatter}; -use super::{Instruction, InstructionBuilder, Operand, Operation, TypeCode}; +use super::{Instruction, InstructionFields, Operand, Operation, TypeCode}; pub struct Multiply { pub destination: u16, @@ -36,7 +36,7 @@ impl From for Instruction { let b_type = multiply.left_type; let c_type = multiply.right_type; - InstructionBuilder { + InstructionFields { operation, a_field, b_field, diff --git a/dust-lang/src/instruction/negate.rs b/dust-lang/src/instruction/negate.rs index bc3c14d..d11404c 100644 --- a/dust-lang/src/instruction/negate.rs +++ b/dust-lang/src/instruction/negate.rs @@ -1,6 +1,6 @@ use std::fmt::{self, Display, Formatter}; -use super::{Instruction, InstructionBuilder, Operand, Operation, TypeCode}; +use super::{Instruction, InstructionFields, Operand, Operation, TypeCode}; pub struct Negate { pub destination: u16, @@ -29,7 +29,7 @@ impl From for Instruction { let (b_field, b_is_constant) = negate.argument.as_index_and_constant_flag(); let b_type = negate.argument_type; - InstructionBuilder { + InstructionFields { operation, a_field, b_field, diff --git a/dust-lang/src/instruction/not.rs b/dust-lang/src/instruction/not.rs index c74b822..dc0238e 100644 --- a/dust-lang/src/instruction/not.rs +++ b/dust-lang/src/instruction/not.rs @@ -2,7 +2,7 @@ use std::fmt::Display; use crate::{Instruction, Operand, Operation}; -use super::InstructionBuilder; +use super::InstructionFields; pub struct Not { pub destination: u16, @@ -27,7 +27,7 @@ impl From for Instruction { let a_field = not.destination; let (b_field, b_is_constant) = not.argument.as_index_and_constant_flag(); - InstructionBuilder { + InstructionFields { operation, a_field, b_field, diff --git a/dust-lang/src/instruction/point.rs b/dust-lang/src/instruction/point.rs index 4ba8914..5013b1f 100644 --- a/dust-lang/src/instruction/point.rs +++ b/dust-lang/src/instruction/point.rs @@ -2,7 +2,7 @@ use std::fmt::{self, Display, Formatter}; use crate::{Instruction, Operation}; -use super::{InstructionBuilder, Operand}; +use super::{InstructionFields, Operand}; pub struct Point { pub destination: u16, @@ -24,7 +24,7 @@ impl From for Instruction { let a_field = r#move.destination; let (b_field, b_is_constant) = r#move.to.as_index_and_constant_flag(); - InstructionBuilder { + InstructionFields { operation, a_field, b_field, diff --git a/dust-lang/src/instruction/return.rs b/dust-lang/src/instruction/return.rs index f708700..ace01ad 100644 --- a/dust-lang/src/instruction/return.rs +++ b/dust-lang/src/instruction/return.rs @@ -2,7 +2,7 @@ use std::fmt::{self, Display, Formatter}; use crate::{Instruction, Operation}; -use super::{InstructionBuilder, TypeCode}; +use super::{InstructionFields, TypeCode}; pub struct Return { pub should_return_value: bool, @@ -31,7 +31,7 @@ impl From for Instruction { let b_type = r#return.r#type; let c_field = r#return.return_register; - InstructionBuilder { + InstructionFields { operation, b_field, b_type, diff --git a/dust-lang/src/instruction/subtract.rs b/dust-lang/src/instruction/subtract.rs index 994b0c3..1381788 100644 --- a/dust-lang/src/instruction/subtract.rs +++ b/dust-lang/src/instruction/subtract.rs @@ -1,6 +1,6 @@ use std::fmt::{self, Display, Formatter}; -use super::{Instruction, InstructionBuilder, Operand, Operation, TypeCode}; +use super::{Instruction, InstructionFields, Operand, Operation, TypeCode}; pub struct Subtract { pub destination: u16, @@ -36,7 +36,7 @@ impl From for Instruction { let b_type = subtract.left_type; let c_type = subtract.right_type; - InstructionBuilder { + InstructionFields { operation, a_field, b_field, diff --git a/dust-lang/src/instruction/test.rs b/dust-lang/src/instruction/test.rs index e826ed3..692457a 100644 --- a/dust-lang/src/instruction/test.rs +++ b/dust-lang/src/instruction/test.rs @@ -2,7 +2,7 @@ use std::fmt::{self, Display, Formatter}; use crate::{Instruction, Operation}; -use super::InstructionBuilder; +use super::InstructionFields; pub struct Test { pub operand_register: u16, @@ -26,7 +26,7 @@ impl From for Instruction { let b_field = test.operand_register; let c_field = test.test_value as u16; - InstructionBuilder { + InstructionFields { operation: Operation::TEST, b_field, c_field, diff --git a/dust-lang/src/instruction/test_set.rs b/dust-lang/src/instruction/test_set.rs index 55b1b0e..f4ef536 100644 --- a/dust-lang/src/instruction/test_set.rs +++ b/dust-lang/src/instruction/test_set.rs @@ -2,7 +2,7 @@ use std::fmt::{self, Display, Formatter}; use crate::{Instruction, Operand, Operation}; -use super::InstructionBuilder; +use super::InstructionFields; pub struct TestSet { pub destination: u16, @@ -31,7 +31,7 @@ impl From for Instruction { let (b_field, b_is_constant) = test_set.argument.as_index_and_constant_flag(); let c_field = test_set.test_value as u16; - InstructionBuilder { + InstructionFields { operation, a_field, b_field, diff --git a/dust-lang/src/value/concrete_value.rs b/dust-lang/src/value/concrete_value.rs index f923d2a..998df21 100644 --- a/dust-lang/src/value/concrete_value.rs +++ b/dust-lang/src/value/concrete_value.rs @@ -35,6 +35,46 @@ impl ConcreteValue { ConcreteValue::String(to_string.into()) } + pub fn as_boolean(&self) -> Option { + if let ConcreteValue::Boolean(boolean) = self { + Some(*boolean) + } else { + None + } + } + + pub fn as_byte(&self) -> Option { + if let ConcreteValue::Byte(byte) = self { + Some(*byte) + } else { + None + } + } + + pub fn as_character(&self) -> Option { + if let ConcreteValue::Character(character) = self { + Some(*character) + } else { + None + } + } + + pub fn as_float(&self) -> Option { + if let ConcreteValue::Float(float) = self { + Some(*float) + } else { + None + } + } + + pub fn as_integer(&self) -> Option { + if let ConcreteValue::Integer(integer) = self { + Some(*integer) + } else { + None + } + } + pub fn as_string(&self) -> Option<&DustString> { if let ConcreteValue::String(string) = self { Some(string) @@ -43,6 +83,22 @@ impl ConcreteValue { } } + pub fn as_list(&self) -> Option<&Vec> { + if let ConcreteValue::List(list) = self { + Some(list) + } else { + None + } + } + + pub fn as_range(&self) -> Option<&RangeValue> { + if let ConcreteValue::Range(range) = self { + Some(range) + } else { + None + } + } + pub fn display(&self) -> DustString { DustString::from(self.to_string()) } @@ -147,7 +203,7 @@ impl ConcreteValue { return Err(ValueError::CannotMultiply( self.clone().to_value(), other.clone().to_value(), - )) + )); } }; @@ -165,7 +221,7 @@ impl ConcreteValue { return Err(ValueError::CannotMultiply( self.clone().to_value(), other.clone().to_value(), - )) + )); } }; @@ -185,7 +241,7 @@ impl ConcreteValue { return Err(ValueError::CannotMultiply( self.clone().to_value(), other.clone().to_value(), - )) + )); } }; @@ -255,7 +311,7 @@ impl ConcreteValue { return Err(ValueError::CannotCompare( self.clone().to_value(), other.clone().to_value(), - )) + )); } }; @@ -278,7 +334,7 @@ impl ConcreteValue { return Err(ValueError::CannotCompare( self.clone().to_value(), other.clone().to_value(), - )) + )); } }; diff --git a/dust-lang/src/vm/action.rs b/dust-lang/src/vm/action.rs index a99bddb..bf5417b 100644 --- a/dust-lang/src/vm/action.rs +++ b/dust-lang/src/vm/action.rs @@ -1,16 +1,9 @@ -use tracing::trace; - use crate::{ - AbstractList, ConcreteValue, Instruction, Operand, Type, Value, - instruction::{ - Add, Call, CallNative, Divide, Equal, InstructionBuilder, Jump, Less, LessEqual, - LoadBoolean, LoadConstant, LoadFunction, LoadList, LoadSelf, Modulo, Multiply, Negate, Not, - Return, Subtract, Test, TestSet, TypeCode, - }, - vm::CallFrame, + Instruction, Value, + instruction::{InstructionFields, TypeCode}, }; -use super::{Pointer, Register, thread::Thread}; +use super::thread::Thread; #[derive(Debug)] pub struct ActionSequence { @@ -34,20 +27,20 @@ impl ActionSequence { #[derive(Clone, Copy, Debug, PartialEq)] pub struct Action { pub logic: RunnerLogic, - pub instruction: InstructionBuilder, + pub instruction: InstructionFields, } impl From<&Instruction> for Action { fn from(instruction: &Instruction) -> Self { let operation = instruction.operation(); let logic = RUNNER_LOGIC_TABLE[operation.0 as usize]; - let instruction = InstructionBuilder::from(instruction); + let instruction = InstructionFields::from(instruction); Action { logic, instruction } } } -pub type RunnerLogic = fn(InstructionBuilder, &mut Thread); +pub type RunnerLogic = fn(InstructionFields, &mut Thread); pub const RUNNER_LOGIC_TABLE: [RunnerLogic; 23] = [ point, @@ -75,21 +68,21 @@ pub const RUNNER_LOGIC_TABLE: [RunnerLogic; 23] = [ r#return, ]; -pub fn point(instruction: InstructionBuilder, thread: &mut Thread) {} +pub fn point(instruction: InstructionFields, thread: &mut Thread) {} -pub fn close(instruction: InstructionBuilder, thread: &mut Thread) {} +pub fn close(instruction: InstructionFields, thread: &mut Thread) {} -pub fn load_boolean(instruction: InstructionBuilder, thread: &mut Thread) {} +pub fn load_boolean(instruction: InstructionFields, thread: &mut Thread) {} -pub fn load_constant(instruction: InstructionBuilder, thread: &mut Thread) {} +pub fn load_constant(instruction: InstructionFields, thread: &mut Thread) {} -pub fn load_list(instruction: InstructionBuilder, thread: &mut Thread) {} +pub fn load_list(instruction: InstructionFields, thread: &mut Thread) {} -pub fn load_function(instruction: InstructionBuilder, thread: &mut Thread) {} +pub fn load_function(instruction: InstructionFields, thread: &mut Thread) {} -pub fn load_self(instruction: InstructionBuilder, thread: &mut Thread) {} +pub fn load_self(instruction: InstructionFields, thread: &mut Thread) {} -pub fn add(instruction: InstructionBuilder, thread: &mut Thread) { +pub fn add(instruction: InstructionFields, thread: &mut Thread) { let destination = instruction.a_field as usize; let left = instruction.b_field as usize; let left_is_constant = instruction.b_is_constant; @@ -161,35 +154,81 @@ pub fn add(instruction: InstructionBuilder, thread: &mut Thread) { } } -pub fn subtract(instruction: InstructionBuilder, thread: &mut Thread) {} +pub fn subtract(instruction: InstructionFields, thread: &mut Thread) {} -pub fn multiply(instruction: InstructionBuilder, thread: &mut Thread) {} +pub fn multiply(instruction: InstructionFields, thread: &mut Thread) {} -pub fn divide(instruction: InstructionBuilder, thread: &mut Thread) {} +pub fn divide(instruction: InstructionFields, thread: &mut Thread) {} -pub fn modulo(instruction: InstructionBuilder, thread: &mut Thread) {} +pub fn modulo(instruction: InstructionFields, thread: &mut Thread) {} -pub fn test(instruction: InstructionBuilder, thread: &mut Thread) {} +pub fn test(instruction: InstructionFields, thread: &mut Thread) {} -pub fn test_set(instruction: InstructionBuilder, thread: &mut Thread) {} +pub fn test_set(instruction: InstructionFields, thread: &mut Thread) {} -pub fn equal(instruction: InstructionBuilder, thread: &mut Thread) {} +pub fn equal(instruction: InstructionFields, thread: &mut Thread) {} -pub fn less(instruction: InstructionBuilder, thread: &mut Thread) {} +pub fn less(instruction: InstructionFields, thread: &mut Thread) { + let comparator = instruction.d_field; + let left = instruction.b_field as usize; + let left_type = instruction.b_type; + let left_is_constant = instruction.b_is_constant; + let right = instruction.c_field as usize; + let right_type = instruction.c_type; + let right_is_constant = instruction.c_is_constant; -pub fn less_equal(instruction: InstructionBuilder, thread: &mut Thread) {} + match (left_type, right_type) { + (TypeCode::INTEGER, TypeCode::INTEGER) => { + 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) + }; + let result = left_value < right_value; -pub fn negate(instruction: InstructionBuilder, thread: &mut Thread) {} + if result == comparator { + thread.current_frame_mut().ip += 1; + } + } + _ => unimplemented!(), + } +} -pub fn not(instruction: InstructionBuilder, thread: &mut Thread) {} +pub fn less_equal(instruction: InstructionFields, thread: &mut Thread) {} -pub fn jump(instruction: InstructionBuilder, thread: &mut Thread) {} +pub fn negate(instruction: InstructionFields, thread: &mut Thread) {} -pub fn call(instruction: InstructionBuilder, thread: &mut Thread) {} +pub fn not(instruction: InstructionFields, thread: &mut Thread) {} -pub fn call_native(instruction: InstructionBuilder, thread: &mut Thread) {} +pub fn jump(instruction: InstructionFields, thread: &mut Thread) { + let offset = instruction.b_field as usize; + let is_positive = instruction.c_field != 0; -pub fn r#return(instruction: InstructionBuilder, thread: &mut Thread) { + if is_positive { + thread.current_frame_mut().ip += offset; + } else { + thread.current_frame_mut().ip -= offset; + } +} + +pub fn call(instruction: InstructionFields, thread: &mut Thread) {} + +pub fn call_native(instruction: InstructionFields, thread: &mut Thread) {} + +pub fn r#return(instruction: InstructionFields, thread: &mut Thread) { let should_return_value = instruction.b_field != 0; let return_register = instruction.c_field as usize; let return_type = instruction.b_type; diff --git a/dust-lang/src/vm/thread.rs b/dust-lang/src/vm/thread.rs index 4814c69..a0057de 100644 --- a/dust-lang/src/vm/thread.rs +++ b/dust-lang/src/vm/thread.rs @@ -2,7 +2,7 @@ use std::{sync::Arc, thread::JoinHandle}; use tracing::{info, trace}; -use crate::{Chunk, DustString, Span, Value, vm::CallFrame}; +use crate::{Chunk, ConcreteValue, DustString, Span, Value, vm::CallFrame}; use super::call_frame::{Pointer, Register}; @@ -557,7 +557,7 @@ impl Thread { *register = Register::Value(value); } - pub fn get_constant(&self, constant_index: usize) -> &Value { + pub fn get_constant(&self, constant_index: usize) -> &ConcreteValue { if cfg!(debug_assertions) { self.chunk.constants.get(constant_index).unwrap() } else {