1
0

Add jump incrementing when emitting return instructions

This commit is contained in:
Jeff 2024-12-30 20:34:06 -05:00
parent 86bdf0bc37
commit 10c66b3f95
5 changed files with 111 additions and 45 deletions

View File

@ -938,7 +938,7 @@ impl<'src> Compiler<'src> {
self.instructions self.instructions
.push((last_instruction, last_type, last_position)); .push((last_instruction, last_type, last_position));
self.next_register() - 1 self.next_register().saturating_sub(1)
}; };
let operator = self.current_token; let operator = self.current_token;
let operator_position = self.current_position; let operator_position = self.current_position;
@ -962,11 +962,17 @@ impl<'src> Compiler<'src> {
self.advance()?; self.advance()?;
self.parse_sub_expression(&rule.precedence)?; self.parse_sub_expression(&rule.precedence)?;
let instructions_length = self.instructions.len() - 1; let instructions_length = self.instructions.len();
for (group_index, instructions) in self.instructions.rchunks_mut(3).enumerate().rev() { for (group_index, instructions) in self.instructions.rchunks_mut(3).enumerate().rev() {
if instructions[0].0.operation() != Operation::TEST if instructions.len() < 3 {
|| instructions[1].0.operation() != Operation::JUMP continue;
}
if !matches!(
instructions[0].0.operation(),
Operation::TEST | Operation::EQUAL | Operation::LESS | Operation::LESS_EQUAL
) || !matches!(instructions[1].0.operation(), Operation::JUMP)
{ {
continue; continue;
} }
@ -1152,10 +1158,29 @@ impl<'src> Compiler<'src> {
self.advance()?; self.advance()?;
self.parse_expression()?; self.parse_expression()?;
let operand_register = self.next_register() - 1; let emit_test_and_jump = if matches!(
let test = Instruction::test(operand_register, true); self.get_last_operations(),
Some([
Operation::EQUAL | Operation::LESS | Operation::LESS_EQUAL,
Operation::JUMP,
Operation::LOAD_BOOLEAN,
Operation::LOAD_BOOLEAN
]),
) {
self.instructions.pop();
self.instructions.pop();
self.emit_instruction(test, Type::None, self.current_position); false
} else {
true
};
if emit_test_and_jump {
let operand_register = self.next_register() - 1;
let test = Instruction::test(operand_register, true);
self.emit_instruction(test, Type::None, self.current_position);
}
let if_block_start = self.instructions.len(); let if_block_start = self.instructions.len();
let if_block_start_position = self.current_position; let if_block_start_position = self.current_position;
@ -1173,7 +1198,7 @@ impl<'src> Compiler<'src> {
let if_block_end = self.instructions.len(); let if_block_end = self.instructions.len();
let mut if_block_distance = (if_block_end - if_block_start) as u8; let mut if_block_distance = (if_block_end - if_block_start) as u8;
let if_block_type = self.get_last_instruction_type(); let if_block_type = self.get_last_instruction_type();
let if_last_register = self.next_register().saturating_sub(1); // let if_last_register = self.next_register().saturating_sub(1);
if let Token::Else = self.current_token { if let Token::Else = self.current_token {
self.advance()?; self.advance()?;
@ -1236,19 +1261,21 @@ impl<'src> Compiler<'src> {
} }
} }
let jump = Instruction::jump(if_block_distance, true); if emit_test_and_jump {
let jump = Instruction::jump(if_block_distance, true);
self.instructions self.instructions
.insert(if_block_start, (jump, Type::None, if_block_start_position)); .insert(if_block_start, (jump, Type::None, if_block_start_position));
}
control_flow_register_consolidation(self); control_flow_register_consolidation(self);
let else_last_register = self.next_register().saturating_sub(1); // let else_last_register = self.next_register().saturating_sub(1);
let point = Instruction::point(else_last_register, if_last_register); // let point = Instruction::point(else_last_register, if_last_register);
if if_last_register < else_last_register { // if if_last_register < else_last_register {
self.emit_instruction(point, else_block_type, self.current_position); // self.emit_instruction(point, else_block_type, self.current_position);
} // }
Ok(()) Ok(())
} }
@ -1406,6 +1433,22 @@ impl<'src> Compiler<'src> {
self.emit_instruction(r#return, Type::None, Span(start, end)); self.emit_instruction(r#return, Type::None, Span(start, end));
let instruction_length = self.instructions.len();
for (index, (instruction, _, _)) in self.instructions.iter_mut().enumerate() {
if instruction.operation() == Operation::JUMP {
let Jump {
offset,
is_positive,
} = Jump::from(&*instruction);
let offset = offset as usize;
if is_positive && offset + index == instruction_length - 2 {
*instruction = Instruction::jump((offset + 1) as u8, true);
}
}
}
Ok(()) Ok(())
} }
@ -1432,6 +1475,22 @@ impl<'src> Compiler<'src> {
self.emit_instruction(r#return, Type::None, self.current_position); self.emit_instruction(r#return, Type::None, self.current_position);
} }
let instruction_length = self.instructions.len();
for (index, (instruction, _, _)) in self.instructions.iter_mut().enumerate() {
if instruction.operation() == Operation::JUMP {
let Jump {
offset,
is_positive,
} = Jump::from(&*instruction);
let offset = offset as usize;
if is_positive && offset + index == instruction_length - 2 {
*instruction = Instruction::jump((offset + 1) as u8, true);
}
}
}
Ok(()) Ok(())
} }

View File

@ -41,15 +41,16 @@ pub fn write(
let mut stdout = stdout(); let mut stdout = stdout();
for register_index in argument_range { for register_index in argument_range {
let value = record.open_register(register_index); if let Some(value) = record.open_register_allow_empty(register_index) {
let string = value.display(record); let string = value.display(record);
stdout stdout
.write(string.as_bytes()) .write(string.as_bytes())
.map_err(|io_error| NativeFunctionError::Io { .map_err(|io_error| NativeFunctionError::Io {
error: io_error.kind(), error: io_error.kind(),
position: record.current_position(), position: record.current_position(),
})?; })?;
}
} }
stdout.flush().map_err(|io_error| NativeFunctionError::Io { stdout.flush().map_err(|io_error| NativeFunctionError::Io {
@ -68,21 +69,22 @@ pub fn write_line(
let mut stdout = stdout().lock(); let mut stdout = stdout().lock();
for register_index in argument_range { for register_index in argument_range {
let value = record.open_register(register_index); if let Some(value) = record.open_register_allow_empty(register_index) {
let string = value.display(record); let string = value.display(record);
stdout stdout
.write(string.as_bytes()) .write(string.as_bytes())
.map_err(|io_error| NativeFunctionError::Io { .map_err(|io_error| NativeFunctionError::Io {
error: io_error.kind(), error: io_error.kind(),
position: record.current_position(), position: record.current_position(),
})?; })?;
stdout stdout
.write(b"\n") .write(b"\n")
.map_err(|io_error| NativeFunctionError::Io { .map_err(|io_error| NativeFunctionError::Io {
error: io_error.kind(), error: io_error.kind(),
position: record.current_position(), position: record.current_position(),
})?; })?;
}
} }
stdout.flush().map_err(|io_error| NativeFunctionError::Io { stdout.flush().map_err(|io_error| NativeFunctionError::Io {

View File

@ -38,6 +38,10 @@ impl CallStack {
self.calls.last() self.calls.last()
} }
pub fn last_mut(&mut self) -> Option<&mut FunctionCall> {
self.calls.last_mut()
}
pub fn pop_or_panic(&mut self) -> FunctionCall { pub fn pop_or_panic(&mut self) -> FunctionCall {
assert!(!self.is_empty(), "{}", VmError::CallStackUnderflow); assert!(!self.is_empty(), "{}", VmError::CallStackUnderflow);

View File

@ -82,7 +82,10 @@ impl Thread {
if record_index == active.index() as usize { if record_index == active.index() as usize {
trace!("Recursion detected"); trace!("Recursion detected");
self.call_stack.last_mut_or_panic().ip = active.ip; if let Some(record) = self.call_stack.last_mut() {
record.ip = active.ip;
}
active.ip = 0; active.ip = 0;
} }
@ -133,10 +136,8 @@ impl Thread {
} }
} }
}; };
let outer_call = self.call_stack.last_or_panic(); let outer_call = self.call_stack.last();
let record_index = outer_call.record_index as usize; let record_index = outer_call.map_or(0, |call| call.record_index as usize);
trace!("Return from {returning_call} to {outer_call}");
if should_return_value { if should_return_value {
let return_register = active let return_register = active
@ -153,7 +154,7 @@ impl Thread {
); );
} else { } else {
active = &mut self.records[record_index]; active = &mut self.records[record_index];
active.ip = outer_call.ip; active.ip = record_index;
} }
} }
} }

View File

@ -5,4 +5,4 @@ fn fib (n: int) -> int {
fib(n - 1) + fib(n - 2) fib(n - 1) + fib(n - 2)
} }
write_line(fib(1)) write_line(fib(0))