فهرست منبع

Fixed bug in optimization

The *dst should be removed from the vector of loaded registers if it cannot be
resolved statically.
Cesar Rodas 10 ماه پیش
والد
کامیت
43b7aa39c7
1فایلهای تغییر یافته به همراه88 افزوده شده و 6 حذف شده
  1. 88 6
      utxo/src/filter_expr/filter.rs

+ 88 - 6
utxo/src/filter_expr/filter.rs

@@ -70,6 +70,33 @@ impl Filter {
                 OpCode::LOAD(dst, value) => {
                     register.insert(*dst, value.clone());
                 }
+                OpCode::JMP(_)
+                | OpCode::HLT(_)
+                | OpCode::JEQ(_, _)
+                | OpCode::JNE(_, _)
+                | OpCode::LABEL(_) => {}
+                OpCode::MOV(dst, src) => {
+                    if let Some(value) = register.remove(src) {
+                        register.insert(*dst, value);
+                    }
+                }
+                OpCode::LOAD_EXTERNAL(dst, _)
+                | OpCode::AND(dst, _, _)
+                | OpCode::OR(dst, _, _)
+                | OpCode::NOT(dst, _)
+                | OpCode::MOD(dst, _, _)
+                | OpCode::NE(dst, _, _)
+                | OpCode::GT(dst, _, _)
+                | OpCode::LT(dst, _, _)
+                | OpCode::NEG(dst, _)
+                | OpCode::SHL(dst, _, _)
+                | OpCode::XOR(dst, _, _)
+                | OpCode::SHR(dst, _, _)
+                | OpCode::GE(dst, _, _)
+                | OpCode::LE(dst, _, _)
+                | OpCode::CPY(dst, _) => {
+                    register.remove(dst);
+                }
                 OpCode::JEQ(reg, addr) => {
                     if let Some(Value::Bool(true)) = register.get(reg) {
                         *opcode = OpCode::JMP(*addr);
@@ -84,14 +111,17 @@ impl Filter {
                     let value1 = if let Some(value) = register.get(reg1) {
                         value.clone()
                     } else {
+                        register.remove(dst);
                         return;
                     };
                     let value2 = if let Some(value) = register.get(reg2) {
                         value.clone()
                     } else {
+                        register.remove(dst);
                         return;
                     };
                     let result = value1 == value2;
+                    register.insert(*dst, result.into());
                     *opcode = OpCode::LOAD(*dst, result.into());
                 }
                 OpCode::MUL(dst, reg1, reg2)
@@ -100,13 +130,18 @@ impl Filter {
                 | OpCode::ADD(dst, reg1, reg2) => {
                     let number1 = match register.get(reg1) {
                         Some(Value::Number(number)) => *number,
-                        _ => return,
+                        _ => {
+                            register.remove(dst);
+                            return;
+                        }
                     };
                     let number2 = match register.get(reg2) {
                         Some(Value::Number(number)) => *number,
-                        _ => return,
+                        _ => {
+                            register.remove(dst);
+                            return;
+                        }
                     };
-
                     if let Some(calculated_value) = match opcode {
                         OpCode::ADD(_, _, _) => number1.checked_add(number2).map(Value::Number),
                         OpCode::MUL(_, _, _) => number1.checked_mul(number2).map(Value::Number),
@@ -117,9 +152,10 @@ impl Filter {
                         register.insert(*dst, calculated_value.clone());
                         *opcode = OpCode::LOAD(*dst, calculated_value);
                         has_changed = true;
+                    } else {
+                        register.remove(dst);
                     }
                 }
-                _ => {}
             };
         });
         has_changed
@@ -169,6 +205,7 @@ impl Filter {
             | OpCode::MUL(set, reg1, reg2)
             | OpCode::NE(set, reg1, reg2)
             | OpCode::GE(set, reg1, reg2)
+            | OpCode::DIV(set, reg1, reg2)
             | OpCode::LE(set, reg1, reg2)
             | OpCode::GT(set, reg1, reg2)
             | OpCode::LT(set, reg1, reg2)
@@ -302,6 +339,35 @@ impl Filter {
         (self, old_total_opcodes != new_total_opcodes)
     }
 
+    pub fn remove_redundant_load_and_mov(mut self) -> (Self, bool) {
+        let old_total_opcodes = self.opcodes.len();
+        let new_opcodes = self
+            .opcodes
+            .into_iter()
+            .fold(Vec::new(), |mut acc, current| {
+                if let OpCode::MOV(target, from) = &current {
+                    if let Some(last) = acc.last_mut() {
+                        println!("herex: {:?} {:?}", last, current);
+                        match last {
+                            OpCode::LOAD(reg, _) => {
+                                if reg == from {
+                                    *reg = *target;
+                                    return acc;
+                                }
+                            }
+                            _ => {}
+                        }
+                    }
+                }
+                acc.push(current);
+                acc
+            });
+        self.opcodes = new_opcodes;
+        let new_total_opcodes = self.opcodes.len();
+
+        (self, old_total_opcodes != new_total_opcodes)
+    }
+
     /// Attempts to optiomize the `raw_opcodes` inside the Filter. Returns a tuple with the new
     /// self with the optimized opcodes, and a boolean indicating if the program was optimized.
     pub fn optimize_round(mut self) -> (Self, bool) {
@@ -309,6 +375,8 @@ impl Filter {
         let has_changed_register_addresses = self.assign_unique_register_addresses();
         let (mut new_self, has_removed_unused_values) = self.remove_unused_values();
         let (mut new_self, has_removed_useless_jumps) = new_self.remove_useless_jumps();
+        let (mut new_self, has_removed_redundant_load_and_mov) =
+            new_self.remove_redundant_load_and_mov();
 
         new_self.opcodes_to_execute =
             Compiler::resolve_label_to_addr(new_self.opcodes.clone()).unwrap();
@@ -318,7 +386,8 @@ impl Filter {
             has_calculated_static_values
                 || has_removed_unused_values
                 || has_changed_register_addresses
-                || has_removed_useless_jumps,
+                || has_removed_useless_jumps
+                || has_removed_redundant_load_and_mov,
         )
     }
 
@@ -370,7 +439,7 @@ mod test {
             r#"
             WHERE
                 $foo = 3 + 2 * 4 / 2 * 298210 + $bar
-                AND 25 = 5*5
+                AND 25 = 5*$five
         "#,
         )
         .unwrap();
@@ -388,6 +457,7 @@ mod test {
         let external_variables_1 = vec![
             ("foo".into(), ValueOrRef::Value(0.into())),
             ("bar".into(), ValueOrRef::Value(0.into())),
+            ("five".into(), ValueOrRef::Value(5.into())),
         ]
         .into_iter()
         .collect();
@@ -395,6 +465,15 @@ mod test {
         let external_variables_2 = vec![
             ("foo".into(), ValueOrRef::Value(1192844.into())),
             ("bar".into(), ValueOrRef::Value(1.into())),
+            ("five".into(), ValueOrRef::Value(4.into())),
+        ]
+        .into_iter()
+        .collect();
+
+        let external_variables_3 = vec![
+            ("foo".into(), ValueOrRef::Value(1192844.into())),
+            ("bar".into(), ValueOrRef::Value(1.into())),
+            ("five".into(), ValueOrRef::Value(5.into())),
         ]
         .into_iter()
         .collect();
@@ -403,6 +482,9 @@ mod test {
         assert!(matches!(value, Value::Bool(false)));
 
         let value = x.execute(&external_variables_2).expect("valid execution");
+        assert!(matches!(value, Value::Bool(false)));
+
+        let value = x.execute(&external_variables_3).expect("valid execution");
         assert!(matches!(value, Value::Bool(true)));
     }
 }