瀏覽代碼

Fixed bug in optimization

The *dst should be removed from the vector of loaded registers if it cannot be
resolved statically.
Cesar Rodas 9 月之前
父節點
當前提交
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)));
     }
 }