From 0ea99b7d591a8a352187b6745d864bb0f31e6088 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 f40fcda1f6b6842117f02b6cd252a8e150635aa7 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 898d096e39e1d6765b531611265456d022eb550f 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 8013548bbb74f10577ea429f5a9c6f1dcfa6bd64 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 c09f4cf28e5e100534541c30cbc6ccd2b73fc81c 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;