diff --git a/CHANGELOG.md b/CHANGELOG.md index 9719a61a..dae40cbf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,9 @@ ## [Unreleased] ### Enhancements + +* Add `pushDownMov` optimization +* Improve `pullUpMov` optimization * Add `clr` and `fil` support in incremental evaluator before main loop ## v26.6.7 diff --git a/src/eval/optimizer.cpp b/src/eval/optimizer.cpp index 261496a6..7d4108ed 100644 --- a/src/eval/optimizer.cpp +++ b/src/eval/optimizer.cpp @@ -68,6 +68,9 @@ bool Optimizer::optimize(Program& p) const { if (pullUpMov(p)) { changed = true; } + if (pushDownMov(p)) { + changed = true; + } if (removeCommutativeDetour(p)) { changed = true; } @@ -969,7 +972,7 @@ bool canMerge(Operation::Type a, Operation::Type b) { } bool Optimizer::pullUpMov(Program& p) const { - // see tests E014 and E015 + // see tests E014, E015, E086 and E087 bool changed = false; for (size_t i = 0; i + 2 < p.ops.size(); i++) { auto& a = p.ops[i]; @@ -1005,6 +1008,42 @@ bool Optimizer::pullUpMov(Program& p) const { return changed; } +bool Optimizer::pushDownMov(Program& p) const { + // see tests E088, E089 and E090 + bool changed = false; + for (size_t i = 0; i + 2 < p.ops.size(); i++) { + auto& a = p.ops[i]; + auto& b = p.ops[i + 1]; + const auto& c = p.ops[i + 2]; + // check operation types + if (a.type != Operation::Type::MOV || c.type != Operation::Type::MOV || (!ProgramUtil::isArithmetic(b.type) && b.type != Operation::Type::SEQ) ) { + continue; + } + // check operand types + if (a.target.type != Operand::Type::DIRECT || + a.source.type != Operand::Type::DIRECT || + b.target.type != Operand::Type::DIRECT || + b.source.type == Operand::Type::INDIRECT || + c.target.type != Operand::Type::DIRECT || + c.source.type != Operand::Type::DIRECT) { + continue; + } + // check operand values + if (a.target.value != b.target.value || a.target.value != c.source.value || a.source.value != c.target.value) { + continue; + } + // okay, we are ready to optimize! + b.target.value = a.source.value; + if (b.source.type == Operand::Type::DIRECT && b.source.value == a.target.value) { + b.source.value = a.source.value; + } + std::swap(a, b); + p.ops.erase(p.ops.begin() + i + 2); + changed = true; + } + return changed; +} + bool isDirectMov(const Operation& op) { return op.type == Operation::Type::MOV && op.target.type == Operand::Type::DIRECT && diff --git a/src/eval/optimizer.hpp b/src/eval/optimizer.hpp index b73ed959..0438540c 100644 --- a/src/eval/optimizer.hpp +++ b/src/eval/optimizer.hpp @@ -39,6 +39,8 @@ class Optimizer { bool pullUpMov(Program &p) const; + bool pushDownMov(Program &p) const; + bool collapseMovChains(Program &p) const; bool removeCommutativeDetour(Program &p) const; diff --git a/tests/optimizer/E012.asm b/tests/optimizer/E012.asm index dd506d13..51ab9b85 100644 --- a/tests/optimizer/E012.asm +++ b/tests/optimizer/E012.asm @@ -3,6 +3,6 @@ mov $2,$0 add $2,17 mov $0,$2 ; out +add $0,17 mov $1,$0 -add $1,17 -mov $0,$1 + diff --git a/tests/optimizer/E088.asm b/tests/optimizer/E088.asm new file mode 100644 index 00000000..5d58cdb9 --- /dev/null +++ b/tests/optimizer/E088.asm @@ -0,0 +1,7 @@ +; in +mov $1,$0 +add $1,6 +mov $0,$1 +; out +add $0,6 +mov $1,$0 diff --git a/tests/optimizer/E089.asm b/tests/optimizer/E089.asm new file mode 100644 index 00000000..129307a2 --- /dev/null +++ b/tests/optimizer/E089.asm @@ -0,0 +1,7 @@ +; in +mov $1,$0 +pow $1,$0 +mov $0,$1 +; out +pow $0,$0 +mov $1,$0 diff --git a/tests/optimizer/E090.asm b/tests/optimizer/E090.asm new file mode 100644 index 00000000..14ef23a1 --- /dev/null +++ b/tests/optimizer/E090.asm @@ -0,0 +1,7 @@ +; in +mov $1,$0 +pow $1,$1 +mov $0,$1 +; out +pow $0,$0 +mov $1,$0