From f5233bfc69aa343ad7cec4d5f2a1c27876f9c785 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Fri, 28 Sep 2018 17:42:34 -0400 Subject: [PATCH 1/5] constant_propagation_pass: Fold EOR operations It's possible to fold cases of exclusive OR operations if they can be known to be an identity operation, or if both operands happen to be known immediates, in which case we can just store the result of the exclusive-OR directly. --- src/ir_opt/constant_propagation_pass.cpp | 38 +++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/src/ir_opt/constant_propagation_pass.cpp b/src/ir_opt/constant_propagation_pass.cpp index 62d9bf01..5b9f7ac5 100644 --- a/src/ir_opt/constant_propagation_pass.cpp +++ b/src/ir_opt/constant_propagation_pass.cpp @@ -11,10 +11,42 @@ #include "ir_opt/passes.h" namespace Dynarmic::Optimization { +namespace { + +// Folds EOR operations based on: +// +// 1. imm_x ^ imm_y -> result +// 2. x ^ 0 -> x +// 3. 0 ^ y -> y +// +void FoldEOR(IR::Inst& inst, bool is_32_bit) { + const auto lhs = inst.GetArg(0); + const auto rhs = inst.GetArg(1); + + const bool is_lhs_immediate = lhs.IsImmediate(); + const bool is_rhs_immediate = rhs.IsImmediate(); + + if (is_lhs_immediate && is_rhs_immediate) { + const u64 result = lhs.GetImmediateAsU64() ^ rhs.GetImmediateAsU64(); + + if (is_32_bit) { + inst.ReplaceUsesWith(IR::Value{static_cast(result)}); + } else { + inst.ReplaceUsesWith(IR::Value{result}); + } + } else if (is_lhs_immediate && lhs.GetImmediateAsU64() == 0) { + inst.ReplaceUsesWith(rhs); + } else if (is_rhs_immediate && rhs.GetImmediateAsU64() == 0) { + inst.ReplaceUsesWith(lhs); + } +} +} // Anonymous namespace void ConstantPropagation(IR::Block& block) { for (auto& inst : block) { - switch (inst.GetOpcode()) { + const auto opcode = inst.GetOpcode(); + + switch (opcode) { case IR::Opcode::LogicalShiftLeft32: case IR::Opcode::LogicalShiftRight32: case IR::Opcode::ArithmeticShiftRight32: @@ -33,6 +65,10 @@ void ConstantPropagation(IR::Block& block) { } break; } + case IR::Opcode::Eor32: + case IR::Opcode::Eor64: + FoldEOR(inst, opcode == IR::Opcode::Eor32); + break; case IR::Opcode::ZeroExtendByteToWord: { if (!inst.AreAllArgsImmediates()) break; From be3ba545e737fde4d1ef45edfdc1c0b748fa249f Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 1 Oct 2018 18:35:31 -0400 Subject: [PATCH 2/5] ir/value: Add member function to check whether or not all bits of a contained value are set This is useful when we wish to know if a contained value is something like 0xFFFFFFFF, as this helps perform constant folding. For example the operation: x & 0xFFFFFFFF can be folded to just x in the 32-bit case. --- src/frontend/ir/value.cpp | 20 ++++++++++++++++++++ src/frontend/ir/value.h | 8 ++++++++ 2 files changed, 28 insertions(+) diff --git a/src/frontend/ir/value.cpp b/src/frontend/ir/value.cpp index d5ba2c62..a7ef2e65 100644 --- a/src/frontend/ir/value.cpp +++ b/src/frontend/ir/value.cpp @@ -174,4 +174,24 @@ u64 Value::GetImmediateAsU64() const { } } +bool Value::HasAllBitsSet() const { + ASSERT(IsImmediate()); + + switch (GetType()) { + case IR::Type::U1: + return GetU1(); + case IR::Type::U8: + return GetU8() == 0xFF; + case IR::Type::U16: + return GetU16() == 0xFFFF; + case IR::Type::U32: + return GetU32() == 0xFFFFFFFF; + case IR::Type::U64: + return GetU64() == 0xFFFFFFFFFFFFFFFF; + default: + ASSERT_MSG(false, "HasAllBitsSet called on an incompatible Value type."); + return false; + } +} + } // namespace Dynarmic::IR diff --git a/src/frontend/ir/value.h b/src/frontend/ir/value.h index 4984ebdd..80f5970c 100644 --- a/src/frontend/ir/value.h +++ b/src/frontend/ir/value.h @@ -74,6 +74,14 @@ public: */ u64 GetImmediateAsU64() const; + /** + * Determines whether or not the contained constant value has all bits set. + * + * @pre The value contains either a U1, U8, U16, U32, or U64 value. + * Breaking this precondition will cause an assertion to be invoked. + */ + bool HasAllBitsSet() const; + private: Type type; From 142978041de32938701c3c8b29d984f5fb779041 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Sat, 29 Sep 2018 03:24:35 -0400 Subject: [PATCH 3/5] constant_propagation_pass: Fold AND operations --- src/ir_opt/constant_propagation_pass.cpp | 42 +++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/src/ir_opt/constant_propagation_pass.cpp b/src/ir_opt/constant_propagation_pass.cpp index 5b9f7ac5..edcea826 100644 --- a/src/ir_opt/constant_propagation_pass.cpp +++ b/src/ir_opt/constant_propagation_pass.cpp @@ -13,7 +13,43 @@ namespace Dynarmic::Optimization { namespace { -// Folds EOR operations based on: +// Folds AND operations based on the following: +// +// 1. imm_x & imm_y -> result +// 2. x & 0 -> 0 +// 3. 0 & y -> 0 +// 4. x & y -> y (where x has all bits set to 1) +// 5. x & y -> x (where y has all bits set to 1) +// +void FoldAND(IR::Inst& inst, bool is_32_bit) { + const auto lhs = inst.GetArg(0); + const auto rhs = inst.GetArg(1); + + const bool is_lhs_immediate = lhs.IsImmediate(); + const bool is_rhs_immediate = rhs.IsImmediate(); + + if (is_lhs_immediate && is_rhs_immediate) { + const u64 result = lhs.GetImmediateAsU64() & rhs.GetImmediateAsU64(); + + if (is_32_bit) { + inst.ReplaceUsesWith(IR::Value{static_cast(result)}); + } else { + inst.ReplaceUsesWith(IR::Value{result}); + } + } else if ((is_lhs_immediate && lhs.GetImmediateAsU64() == 0) || (is_rhs_immediate && rhs.GetImmediateAsU64() == 0)) { + if (is_32_bit) { + inst.ReplaceUsesWith(IR::Value{u32{0}}); + } else { + inst.ReplaceUsesWith(IR::Value{u64{0}}); + } + } else if (is_lhs_immediate && lhs.HasAllBitsSet()) { + inst.ReplaceUsesWith(rhs); + } else if (is_rhs_immediate && rhs.HasAllBitsSet()) { + inst.ReplaceUsesWith(lhs); + } +} + +// Folds EOR operations based on the following: // // 1. imm_x ^ imm_y -> result // 2. x ^ 0 -> x @@ -65,6 +101,10 @@ void ConstantPropagation(IR::Block& block) { } break; } + case IR::Opcode::And32: + case IR::Opcode::And64: + FoldAND(inst, opcode == IR::Opcode::And32); + break; case IR::Opcode::Eor32: case IR::Opcode::Eor64: FoldEOR(inst, opcode == IR::Opcode::Eor32); From 0d1f9841d1f875ead400f115ddeab70175a08fcf Mon Sep 17 00:00:00 2001 From: Lioncash Date: Sat, 29 Sep 2018 03:57:16 -0400 Subject: [PATCH 4/5] constant_propagation_pass: Fold OR operations --- src/ir_opt/constant_propagation_pass.cpp | 32 ++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/ir_opt/constant_propagation_pass.cpp b/src/ir_opt/constant_propagation_pass.cpp index edcea826..f315a3f1 100644 --- a/src/ir_opt/constant_propagation_pass.cpp +++ b/src/ir_opt/constant_propagation_pass.cpp @@ -76,6 +76,34 @@ void FoldEOR(IR::Inst& inst, bool is_32_bit) { inst.ReplaceUsesWith(lhs); } } + +// Folds OR operations based on the following: +// +// 1. imm_x | imm_y -> result +// 2. x | 0 -> x +// 3. 0 | y -> y +// +void FoldOR(IR::Inst& inst, bool is_32_bit) { + const auto lhs = inst.GetArg(0); + const auto rhs = inst.GetArg(1); + + const bool is_lhs_immediate = lhs.IsImmediate(); + const bool is_rhs_immediate = rhs.IsImmediate(); + + if (is_lhs_immediate && is_rhs_immediate) { + const u64 result = lhs.GetImmediateAsU64() | rhs.GetImmediateAsU64(); + + if (is_32_bit) { + inst.ReplaceUsesWith(IR::Value{static_cast(result)}); + } else { + inst.ReplaceUsesWith(IR::Value{result}); + } + } else if (is_lhs_immediate && lhs.GetImmediateAsU64() == 0) { + inst.ReplaceUsesWith(rhs); + } else if (is_rhs_immediate && rhs.GetImmediateAsU64() == 0) { + inst.ReplaceUsesWith(lhs); + } +} } // Anonymous namespace void ConstantPropagation(IR::Block& block) { @@ -109,6 +137,10 @@ void ConstantPropagation(IR::Block& block) { case IR::Opcode::Eor64: FoldEOR(inst, opcode == IR::Opcode::Eor32); break; + case IR::Opcode::Or32: + case IR::Opcode::Or64: + FoldOR(inst, opcode == IR::Opcode::Or32); + break; case IR::Opcode::ZeroExtendByteToWord: { if (!inst.AreAllArgsImmediates()) break; From 7868411de5413f06596fd89db1b1658b38e7e97f Mon Sep 17 00:00:00 2001 From: Lioncash Date: Sat, 29 Sep 2018 04:07:32 -0400 Subject: [PATCH 5/5] constant_propagation_pass: Fold NOT operations --- src/ir_opt/constant_propagation_pass.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/ir_opt/constant_propagation_pass.cpp b/src/ir_opt/constant_propagation_pass.cpp index f315a3f1..4d323bf3 100644 --- a/src/ir_opt/constant_propagation_pass.cpp +++ b/src/ir_opt/constant_propagation_pass.cpp @@ -77,6 +77,21 @@ void FoldEOR(IR::Inst& inst, bool is_32_bit) { } } +// Folds NOT operations if the contained value is an immediate. +void FoldNOT(IR::Inst& inst, bool is_32_bit) { + const auto operand = inst.GetArg(0); + + if (operand.IsImmediate()) { + const u64 result = ~operand.GetImmediateAsU64(); + + if (is_32_bit) { + inst.ReplaceUsesWith(IR::Value{static_cast(result)}); + } else { + inst.ReplaceUsesWith(IR::Value{result}); + } + } +} + // Folds OR operations based on the following: // // 1. imm_x | imm_y -> result @@ -141,6 +156,10 @@ void ConstantPropagation(IR::Block& block) { case IR::Opcode::Or64: FoldOR(inst, opcode == IR::Opcode::Or32); break; + case IR::Opcode::Not32: + case IR::Opcode::Not64: + FoldNOT(inst, opcode == IR::Opcode::Not32); + break; case IR::Opcode::ZeroExtendByteToWord: { if (!inst.AreAllArgsImmediates()) break;