Skip to content

Commit

Permalink
Merge pull request #1006 from candy-lang/smaller-vm-instructions
Browse files Browse the repository at this point in the history
Smaller VM instructions
  • Loading branch information
jwbot authored Apr 18, 2024
2 parents f6afec0 + bf7b63c commit 8c4d446
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 93 deletions.
144 changes: 62 additions & 82 deletions compiler/vm/src/byte_code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,7 @@ pub enum Instruction {
/// Pushes a function.
///
/// a -> a, pointer to function
CreateFunction {
captured: Vec<StackOffset>,
num_args: usize, // excluding responsible parameter
body: InstructionPointer,
},
CreateFunction(Box<CreateFunction>),

/// Pushes a pointer onto the stack. MIR instructions that create
/// compile-time known values are compiled to this instruction.
Expand Down Expand Up @@ -94,7 +90,9 @@ pub enum Instruction {
/// executing the call.
TailCall {
num_locals_to_pop: usize,
num_args: usize, // excluding the responsible argument
// This is `u32` instead of `usize` to reduce the size of the
// enum from 24 to 16 bytes.
num_args: u32, // excluding the responsible argument
},

/// Returns from the current function to the original caller. Leaves the
Expand All @@ -107,12 +105,7 @@ pub enum Instruction {
/// the `condition`.
///
/// a, condition, responsible -> a
IfElse {
then_target: InstructionPointer,
then_captured: Vec<StackOffset>,
else_target: InstructionPointer,
else_captured: Vec<StackOffset>,
},
IfElse(Box<IfElse>),

/// Panics. Because the panic instruction only occurs inside the generated
/// needs function, the reason is already guaranteed to be a text.
Expand All @@ -137,6 +130,19 @@ pub enum Instruction {
/// a, HIR ID, function -> a
TraceFoundFuzzableFunction,
}
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct CreateFunction {
pub captured: Vec<StackOffset>,
pub num_args: usize, // excluding responsible parameter
pub body: InstructionPointer,
}
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct IfElse {
pub then_target: InstructionPointer,
pub then_captured: Vec<StackOffset>,
pub else_target: InstructionPointer,
pub else_captured: Vec<StackOffset>,
}

impl Instruction {
/// Applies the instruction's effect on the stack. After calling it, the
Expand Down Expand Up @@ -187,7 +193,7 @@ impl Instruction {
num_args,
} => {
stack.pop(); // responsible
stack.pop_multiple(*num_args);
stack.pop_multiple((*num_args).try_into().unwrap());
stack.pop(); // function/builtin
stack.pop_multiple(*num_locals_to_pop);
stack.push(result); // return value
Expand All @@ -196,7 +202,7 @@ impl Instruction {
// Only modifies the call stack and the instruction pointer.
// Leaves the return value untouched on the stack.
}
Self::IfElse { .. } => {
Self::IfElse(_) => {
stack.pop(); // responsible
stack.pop(); // condition
stack.push(result); // return value
Expand Down Expand Up @@ -273,7 +279,7 @@ impl ToRichIr for ByteCode {
TokenType::Address,
EnumSet::empty(),
);
builder.push(": ", None, EnumSet::empty());
builder.push_simple(": ");
builder.push(
format!("{constant:?}"),
TokenType::Constant,
Expand Down Expand Up @@ -314,50 +320,42 @@ impl ToRichIr for ByteCode {
}
}
}
impl Instruction {
impl ToRichIr for Instruction {
fn build_rich_ir(&self, builder: &mut RichIrBuilder) {
let discriminant: InstructionDiscriminants = self.into();
builder.push(
Into::<&'static str>::into(discriminant),
None,
EnumSet::empty(),
);
builder.push_simple(Into::<&'static str>::into(discriminant));

match self {
Self::CreateTag { symbol } => {
builder.push(" ", None, EnumSet::empty());
let symbol_range = builder.push(symbol.get(), None, EnumSet::empty());
builder.push_simple(" ");
let symbol_range = builder.push_simple(symbol.get());
builder.push_reference(ReferenceKey::Symbol(symbol.to_string()), symbol_range);
}
Self::CreateList { num_items } => {
builder.push(" ", None, EnumSet::empty());
builder.push(num_items.to_string(), None, EnumSet::empty());
builder.push_simple(" ");
builder.push_simple(num_items.to_string());
}
Self::CreateStruct { num_fields } => {
builder.push(" ", None, EnumSet::empty());
builder.push(num_fields.to_string(), None, EnumSet::empty());
builder.push_simple(" ");
builder.push_simple(num_fields.to_string());
}
Self::CreateFunction {
Self::CreateFunction(box CreateFunction {
captured,
num_args,
body,
} => {
builder.push(
format!(
" with {num_args} {} capturing {} starting at {body:?}",
arguments_plural(*num_args),
if captured.is_empty() {
"nothing".to_string()
} else {
captured.iter().join(", ")
},
),
None,
EnumSet::empty(),
);
}) => {
builder.push_simple(format!(
" with {num_args} {} capturing {} starting at {body:?}",
arguments_plural(*num_args),
if captured.is_empty() {
"nothing".to_string()
} else {
captured.iter().join(", ")
},
));
}
Self::PushConstant(constant) => {
builder.push(" ", None, EnumSet::empty());
builder.push_simple(" ");
if let InlineData::Pointer(pointer) = InlineData::from(*constant) {
builder.push(
format!("{:?}", pointer.get().address()),
Expand All @@ -367,54 +365,46 @@ impl Instruction {
} else {
builder.push("inline", TokenType::Address, EnumSet::empty());
}
builder.push(" ", None, EnumSet::empty());
builder.push_simple(" ");
builder.push(
format!("{constant:?}"),
TokenType::Constant,
EnumSet::empty(),
);
}
Self::PushFromStack(offset) => {
builder.push(" ", None, EnumSet::empty());
builder.push(offset.to_string(), None, EnumSet::empty());
builder.push_simple(" ");
builder.push_simple(offset.to_string());
}
Self::PopMultipleBelowTop(count) => {
builder.push(" ", None, EnumSet::empty());
builder.push(count.to_string(), None, EnumSet::empty());
builder.push_simple(" ");
builder.push_simple(count.to_string());
}
Self::Dup { amount } => {
builder.push(" by ", None, EnumSet::empty());
builder.push(amount.to_string(), None, EnumSet::empty());
builder.push_simple(" by ");
builder.push_simple(amount.to_string());
}
Self::Drop => {}
Self::Call { num_args } => {
builder.push(
format!(" with {num_args} {}", arguments_plural(*num_args)),
None,
EnumSet::empty(),
);
builder.push_simple(format!(" with {num_args} {}", arguments_plural(*num_args)));
}
Self::TailCall {
num_locals_to_pop,
num_args,
} => {
builder.push(
format!(
" with {num_locals_to_pop} locals and {num_args} {}",
arguments_plural(*num_args),
),
None,
EnumSet::empty(),
);
builder.push_simple(format!(
" with {num_locals_to_pop} locals and {num_args} {}",
arguments_plural((*num_args).try_into().unwrap()),
));
}
Self::Return => {}
Self::IfElse {
Self::IfElse(box IfElse {
then_target,
then_captured,
else_target,
else_captured,
} => {
builder.push(
}) => {
builder.push_simple(
format!(
" then call {then_target:?} capturing {} else call {else_target:?} capturing {}",
if then_captured.is_empty() {
Expand All @@ -428,28 +418,18 @@ impl Instruction {
else_captured.iter().join(", ")
},
),
None,
EnumSet::empty(),
);
}
Self::Panic => {}
Self::TraceCallStarts { num_args } | Self::TraceTailCall { num_args } => {
builder.push(
format!(" ({num_args} {})", arguments_plural(*num_args)),
None,
EnumSet::empty(),
);
builder.push_simple(format!(" ({num_args} {})", arguments_plural(*num_args)));
}
Self::TraceCallEnds { has_return_value } => {
builder.push(
if *has_return_value {
" with return value"
} else {
" without return value"
},
None,
EnumSet::empty(),
);
builder.push_simple(if *has_return_value {
" with return value"
} else {
" without return value"
});
}
Self::TraceExpressionEvaluated => {}
Self::TraceFoundFuzzableFunction => {}
Expand Down
10 changes: 5 additions & 5 deletions compiler/vm/src/instructions.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::{
byte_code::Instruction,
byte_code::{CreateFunction, IfElse, Instruction},
heap::{Data, Function, Heap, HirId, InlineObject, List, Struct, Tag, Text},
tracer::Tracer,
vm::{CallHandle, MachineState, Panic},
Expand Down Expand Up @@ -79,11 +79,11 @@ impl MachineState {
self.push_to_data_stack(struct_);
InstructionResult::Done
}
Instruction::CreateFunction {
Instruction::CreateFunction(box CreateFunction {
captured,
num_args,
body,
} => {
}) => {
let captured = captured
.iter()
.map(|offset| self.get_from_data_stack(*offset))
Expand Down Expand Up @@ -148,12 +148,12 @@ impl MachineState {
self.next_instruction = self.call_stack.pop();
InstructionResult::Done
}
Instruction::IfElse {
Instruction::IfElse(box IfElse {
then_target,
then_captured,
else_target,
else_captured,
} => {
}) => {
let responsible = self.pop_from_data_stack();
let condition = Tag::value_into_bool_unchecked(self.pop_from_data_stack(), heap);
let (target, captured) = if condition {
Expand Down
1 change: 1 addition & 0 deletions compiler/vm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
addr_parse_ascii,
allocator_api,
anonymous_lifetime_in_impl_trait,
box_patterns,
iterator_try_collect,
let_chains,
nonzero_ops,
Expand Down
12 changes: 6 additions & 6 deletions compiler/vm/src/lir_to_byte_code.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::{
byte_code::{ByteCode, Instruction, StackOffset},
byte_code::{ByteCode, CreateFunction, IfElse, Instruction, StackOffset},
heap::{Builtin, Function, Heap, HirId, InlineObject, Int, List, Struct, Tag, Text},
instruction_pointer::InstructionPointer,
};
Expand Down Expand Up @@ -150,7 +150,7 @@ impl<'c> LoweringContext<'c> {
};
self.current_instructions.push(Instruction::TailCall {
num_locals_to_pop: self.stack.len() - 1,
num_args,
num_args: num_args.try_into().unwrap(),
});
} else {
let dummy_id = Id::from_usize(0);
Expand Down Expand Up @@ -218,11 +218,11 @@ impl<'c> LoweringContext<'c> {
}
self.emit(
id,
Instruction::CreateFunction {
Instruction::CreateFunction(Box::new(CreateFunction {
captured: captured.iter().map(|id| self.stack.find_id(*id)).collect(),
num_args: self.lir.bodies().get(*body_id).parameter_count(),
body: instruction_pointer,
},
})),
);
}
Expression::Constant(constant_id) => {
Expand Down Expand Up @@ -264,7 +264,7 @@ impl<'c> LoweringContext<'c> {
let else_target = self.get_body(*else_body_id);
self.emit(
id,
Instruction::IfElse {
Instruction::IfElse(Box::new(IfElse {
then_target,
then_captured: then_captured
.iter()
Expand All @@ -275,7 +275,7 @@ impl<'c> LoweringContext<'c> {
.iter()
.map(|id| self.stack.find_id(*id))
.collect(),
},
})),
);
}
Expression::Panic {
Expand Down

0 comments on commit 8c4d446

Please sign in to comment.