Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion rust/src/codegen/arch/aarch64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use crate::types::instructions::Instructions;
use ahash::AHashMap;
use smol_str::SmolStr;
pub fn compile_aarch64(mut instructions: Vec<Instructions>) -> Result<String, VMError> {
specialized_instructions(&mut instructions);
let _ = specialized_instructions(&mut instructions);
let empty_imports: AHashMap<SmolStr, crate::types::value::Value> = AHashMap::new();
let (var_count, _symbol_table) = resolve_symbols(&mut instructions, &empty_imports);
let mut builder = AArch64Builder::new()
Expand Down
5 changes: 4 additions & 1 deletion rust/src/modules/gazle/constant_propagation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ fn extract_push_value(instr: &Instructions) -> Option<Value> {
_ => None,
}
}
pub fn constant_propagation(bytecode: &mut [Instructions]) {
pub fn constant_propagation(bytecode: &mut [Instructions]) -> bool {
const MAX_INLINE_USES: usize = 8;
let mut get_counts: AHashMap<SmolStr, usize> = AHashMap::new();
for instr in bytecode.iter() {
Expand All @@ -38,11 +38,13 @@ pub fn constant_propagation(bytecode: &mut [Instructions]) {
}
}
let mut const_map: AHashMap<SmolStr, Option<Value>> = AHashMap::new();
let mut changed = false;
for i in 0..bytecode.len() {
match &bytecode[i] {
Instructions::Get(name) => {
if let Some(Some(val)) = const_map.get(name) {
bytecode[i] = Instructions::Push(val.clone());
changed = true;
}
}
_ => {
Expand Down Expand Up @@ -72,4 +74,5 @@ pub fn constant_propagation(bytecode: &mut [Instructions]) {
}
}
}
changed
}
6 changes: 4 additions & 2 deletions rust/src/modules/gazle/eliminate_dead_loops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ use crate::modules::gazle::utils::is_pure_loop::is_pure_loop;
use crate::types::instructions::Instructions;
use ahash::AHashMap;
#[inline(always)]
pub fn eliminate_dead_loops(bytecode: Vec<Instructions>) -> Vec<Instructions> {
pub fn eliminate_dead_loops(bytecode: Vec<Instructions>) -> (Vec<Instructions>, bool) {
let mut out: Vec<Instructions> = Vec::new();
let mut changed = false;
let mut index_map: AHashMap<usize, usize> = AHashMap::new();
for (i, inst) in bytecode.iter().enumerate() {
let mut is_eliminated = false;
Expand All @@ -26,6 +27,7 @@ pub fn eliminate_dead_loops(bytecode: Vec<Instructions>) -> Vec<Instructions> {
{
out.truncate(out_start_index);
is_eliminated = true;
changed = true;
}
}
_ => {}
Expand All @@ -36,5 +38,5 @@ pub fn eliminate_dead_loops(bytecode: Vec<Instructions>) -> Vec<Instructions> {
index_map.insert(i, out.len());
out.push(inst.clone());
}
out
(out, changed)
}
8 changes: 7 additions & 1 deletion rust/src/modules/gazle/eliminate_dead_stores.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@ enum Demand {
Drop,
}
#[inline]
pub fn eliminate_dead_stores(bytecode: &mut [Instructions], usage: &Usage) {
pub fn eliminate_dead_stores(bytecode: &mut [Instructions], usage: &Usage) -> bool {
let mut stack_demands: Vec<Demand> = Vec::new();
let mut changed = false;
for i in (0..bytecode.len()).rev() {
let previous = bytecode[i].clone();
let inst = &mut bytecode[i];
match inst {
Instructions::Push(_)
Expand Down Expand Up @@ -49,6 +51,7 @@ pub fn eliminate_dead_stores(bytecode: &mut [Instructions], usage: &Usage) {
Instructions::Val(arg) => {
if !usage.read.contains(arg.as_str()) {
*inst = Instructions::Nop;
changed = true;
continue;
}
}
Expand All @@ -59,6 +62,7 @@ pub fn eliminate_dead_stores(bytecode: &mut [Instructions], usage: &Usage) {
if !usage.read.contains(arg.as_str()) {
stack_demands.push(Demand::Drop);
*inst = Instructions::Nop;
changed = true;
continue;
}
stack_demands.push(Demand::Keep);
Expand Down Expand Up @@ -224,5 +228,7 @@ pub fn eliminate_dead_stores(bytecode: &mut [Instructions], usage: &Usage) {
Instructions::Jump(_) | Instructions::Stop => {}
_ => {}
}
changed |= bytecode[i] != previous;
}
changed
}
8 changes: 5 additions & 3 deletions rust/src/modules/gazle/eliminate_redundant_loads.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,13 @@

use crate::types::instructions::Instructions;
#[inline(always)]
pub fn eliminate_redundant_loads(bytecode: Vec<Instructions>) -> Vec<Instructions> {
pub fn eliminate_redundant_loads(bytecode: Vec<Instructions>) -> (Vec<Instructions>, bool) {
if bytecode.is_empty() {
return bytecode;
return (bytecode, false);
}
let mut optimized = Vec::with_capacity(bytecode.len());
let mut last_origin: Option<Instructions> = None;
let mut changed = false;
for instr in bytecode {
let is_redundant = if let Some(last) = optimized.last() {
let effective_last = if matches!(last, Instructions::Dup) {
Expand All @@ -36,10 +37,11 @@ pub fn eliminate_redundant_loads(bytecode: Vec<Instructions>) -> Vec<Instruction
};
if is_redundant {
optimized.push(Instructions::Dup);
changed = true;
} else {
last_origin = Some(instr.clone());
optimized.push(instr);
}
}
optimized
(optimized, changed)
}
9 changes: 8 additions & 1 deletion rust/src/modules/gazle/fold_constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,9 @@ use crate::types::{instructions::Instructions, value::Value};
use ahash::AHashMap;
use std::sync::Arc;
#[inline(always)]
pub fn fold_constants(bytecode: &mut [Instructions]) {
pub fn fold_constants(bytecode: &mut [Instructions]) -> bool {
let mut i = 0;
let mut changed = false;
while i < bytecode.len() {
if let Some(Instructions::MakeArray(count)) = bytecode.get(i) {
let count = *count as usize;
Expand All @@ -65,6 +66,7 @@ pub fn fold_constants(bytecode: &mut [Instructions]) {
}
}
if all_const {
changed = true;
bytecode[i - count] = Instructions::PushArray(Arc::new(vals));
for instr in bytecode.iter_mut().take(i + 1).skip(i - count + 1) {
*instr = Instructions::Nop;
Expand All @@ -90,6 +92,7 @@ pub fn fold_constants(bytecode: &mut [Instructions]) {
.iter()
.all(|pair| matches!(&pair[0], Value::String(_)));
if operands.len() == operand_count && valid_keys {
changed = true;
let mut object = AHashMap::with_capacity(*count as usize);
for pair in operands.as_chunks::<2>().0.iter().rev() {
let Value::String(key) = &pair[0] else {
Expand Down Expand Up @@ -154,6 +157,7 @@ pub fn fold_constants(bytecode: &mut [Instructions]) {
_ => None,
};
if let Some(res_val) = result {
changed = true;
bytecode[i] = value_to_instruction(res_val);
bytecode[i + 1] = Instructions::Nop;
bytecode[i + 2] = Instructions::Nop;
Expand Down Expand Up @@ -206,6 +210,7 @@ pub fn fold_constants(bytecode: &mut [Instructions]) {
_ => None,
};
if let Some(res_val) = result {
changed = true;
bytecode[i] = value_to_instruction(res_val);
bytecode[i + 1] = Instructions::Nop;
bytecode[i + 2] = Instructions::Nop;
Expand All @@ -215,8 +220,10 @@ pub fn fold_constants(bytecode: &mut [Instructions]) {
}
i += 1;
}
changed
}
#[cfg(test)]
#[allow(unused_must_use)]
mod tests {
use super::*;
use crate::types::{primitive_types::PrimitiveTypes, value::Value};
Expand Down
55 changes: 53 additions & 2 deletions rust/src/modules/gazle/fold_conversions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use crate::instructions::{
cos_func::cos_values, neg_func::neg_values, sin_func::sin_values, tan_func::tan_values,
},
exp_func::exp_values,
logarithm::ln_func::ln_values,
logarithm::{ln_func::ln_values, log2_func::log2_values, log10_func::log10_values},
root::{cbrt_func::cbrt_values, sqrt_func::sqrt_values},
trigonometry::{
hyperbolic::{
Expand Down Expand Up @@ -62,8 +62,9 @@ use crate::modules::gazle::utils::{
};
use crate::types::instructions::Instructions;
#[inline(always)]
pub fn fold_conversions(bytecode: &mut [Instructions]) {
pub fn fold_conversions(bytecode: &mut [Instructions]) -> bool {
let mut i = 0;
let mut changed = false;
while i < bytecode.len().saturating_sub(1) {
let instr1 = &bytecode[i];
let instr2 = &bytecode[i + 1];
Expand Down Expand Up @@ -114,11 +115,14 @@ pub fn fold_conversions(bytecode: &mut [Instructions]) {
Instructions::Lnv(t) => lnv_values(val, *t, i).ok(),
Instructions::Exp(t) => exp_values(val, *t, i).ok(),
Instructions::Expv(t) => expv_values(val, *t, i).ok(),
Instructions::Log2(t) => log2_values(val, *t, i).ok(),
Instructions::Log10(t) => log10_values(val, *t, i).ok(),
Instructions::Log2v(t) => log2v_values(val, *t, i).ok(),
Instructions::Log10v(t) => log10v_values(val, *t, i).ok(),
_ => None,
};
if let Some(res_val) = folded {
changed = true;
bytecode[i] = value_to_instruction(res_val);
bytecode[i + 1] = Instructions::Nop;
i += 2;
Expand All @@ -127,13 +131,60 @@ pub fn fold_conversions(bytecode: &mut [Instructions]) {
}
i += 1;
}
changed
}
#[cfg(test)]
#[allow(unused_must_use)]
mod tests {
use super::*;
use crate::types::{primitive_types::PrimitiveTypes, value::Value};
use std::sync::Arc;
#[test]
fn folds_scalar_logarithms() {
let mut log2 = vec![
Instructions::PushFloat32(8.0),
Instructions::Log2(PrimitiveTypes::Flt),
];
assert!(fold_conversions(&mut log2));
assert_eq!(
log2,
vec![Instructions::PushFloat32(3.0), Instructions::Nop]
);
let mut log10 = vec![
Instructions::PushFloat32(100.0),
Instructions::Log10(PrimitiveTypes::Flt),
];
assert!(fold_conversions(&mut log10));
assert_eq!(
log10,
vec![Instructions::PushFloat32(2.0), Instructions::Nop]
);
}
#[test]
fn leaves_invalid_scalar_logarithms_for_runtime_error() {
for operation in [
Instructions::Log2(PrimitiveTypes::Flt),
Instructions::Log10(PrimitiveTypes::Flt),
] {
let mut bytecode = vec![
Instructions::PushString("invalid".into()),
operation,
Instructions::Stop,
];
let expected = bytecode.clone();
assert!(!fold_conversions(&mut bytecode));
assert_eq!(bytecode, expected);
assert!(matches!(
crate::vm::execute::execute(bytecode, &mut None, None),
Err(crate::modules::vmerror::VMError::TypeMismatch {
ip: 1,
expected: "Float",
found: "String"
})
));
}
}
#[test]
fn folds_valid_unary_float_vectors_and_retains_invalid_ones() {
let operations = [
Instructions::Lnv(PrimitiveTypes::Flt),
Expand Down
6 changes: 5 additions & 1 deletion rust/src/modules/gazle/jump_threading.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@

use crate::types::instructions::Instructions;
#[inline(always)]
pub fn jump_threading(bytecode: &mut [Instructions]) {
pub fn jump_threading(bytecode: &mut [Instructions]) -> bool {
let mut changed = true;
let mut pass_changed = false;
while changed {
changed = false;
for i in 0..bytecode.len() {
Expand All @@ -21,16 +22,19 @@ pub fn jump_threading(bytecode: &mut [Instructions]) {
{
bytecode[i] = Instructions::Jump(final_target);
changed = true;
pass_changed = true;
}
} else if let Instructions::IfFalse(target) = bytecode[i]
&& let Some(final_target) = find_final_target(bytecode, target)
&& final_target != target
{
bytecode[i] = Instructions::IfFalse(final_target);
changed = true;
pass_changed = true;
}
}
}
pass_changed
}
fn find_final_target(bytecode: &[Instructions], mut target: usize) -> Option<usize> {
let mut visited = std::collections::HashSet::new();
Expand Down
19 changes: 16 additions & 3 deletions rust/src/modules/gazle/optimize_bytecode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,9 @@ pub fn optimize_bytecode(
break;
}
let len_before_pass = bytecode.len();
let prev_bytes_debug = bytecode.clone();
run_pass(pass_id, &mut bytecode);
let pass_changed = run_pass(pass_id, &mut bytecode);
let len_after_pass = bytecode.len();
if bytecode != prev_bytes_debug {
if pass_changed {
let reduction = (len_before_pass as i32) - (len_after_pass as i32);
let reward = if reduction > 0 { reduction * 2 } else { 1 };
pass_weights[pass_id] += reward;
Expand Down Expand Up @@ -93,9 +92,23 @@ pub fn optimize_bytecode(
#[cfg(test)]
mod tests {
use super::*;
use crate::modules::gazle::utils::run_pass::run_pass;
use crate::types::{primitive_types::PrimitiveTypes, value::Value};
use smol_str::SmolStr;
#[test]
fn terminates_when_no_pass_reports_a_mutation() {
let bytecode = vec![Instructions::Stop];
for pass_id in 0..9 {
let mut pass_bytecode = bytecode.clone();
assert!(!run_pass(pass_id, &mut pass_bytecode));
assert_eq!(pass_bytecode, bytecode);
}
assert_eq!(
optimize_bytecode(bytecode.clone(), TimeBudgetType::Cheap),
bytecode
);
}
#[test]
fn folds_constant_add_and_concat_to_correct_result() {
let bytecode = vec![
Instructions::Val(SmolStr::new("x")),
Expand Down
5 changes: 4 additions & 1 deletion rust/src/modules/gazle/specialized_instructions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
*/

use crate::types::{instructions::Instructions, value::Value};
pub fn specialized_instructions(bytecode: &mut [Instructions]) {
pub fn specialized_instructions(bytecode: &mut [Instructions]) -> bool {
let mut changed = false;
for instr in bytecode.iter_mut() {
if let Instructions::Push(val) = instr {
let replacement = match val {
Expand All @@ -31,7 +32,9 @@ pub fn specialized_instructions(bytecode: &mut [Instructions]) {
};
if let Some(new_instr) = replacement {
*instr = new_instr;
changed = true;
}
}
}
changed
}
Loading
Loading