From 72daf372081813904ee9906f03c14204ef3c23cf Mon Sep 17 00:00:00 2001 From: Lioncash Date: Sun, 7 Oct 2018 21:48:42 -0400 Subject: [PATCH 1/2] constant_propagation_pass: Fold Mul32 and Mul64 cases where applicable Multiplication operations can currently be folded if: 1. Both arguments are known constant values 2. Either operand is zero (in which case the result is also zero) 3. Either operand is one (in which case the result is the non-one operand). --- src/ir_opt/constant_propagation_pass.cpp | 37 ++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/ir_opt/constant_propagation_pass.cpp b/src/ir_opt/constant_propagation_pass.cpp index a8018711..c18f31cd 100644 --- a/src/ir_opt/constant_propagation_pass.cpp +++ b/src/ir_opt/constant_propagation_pass.cpp @@ -74,6 +74,39 @@ void FoldEOR(IR::Inst& inst, bool is_32_bit) { } } +// Folds multiplication operations based on the following: +// +// 1. imm_x * imm_y -> result +// 2. x * 0 -> 0 +// 3. 0 * y -> 0 +// 4. x * 1 -> x +// 5. 1 * y -> y +// +void FoldMultiply(IR::Inst& inst, bool is_32_bit) { + const auto lhs = inst.GetArg(0); + const auto rhs = inst.GetArg(1); + + if (lhs.IsImmediate() && rhs.IsImmediate()) { + 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 (lhs.IsZero() || rhs.IsZero()) { + if (is_32_bit) { + inst.ReplaceUsesWith(IR::Value{u32{0}}); + } else { + inst.ReplaceUsesWith(IR::Value{u64{0}}); + } + } else if (lhs.IsUnsignedImmediate(1)) { + inst.ReplaceUsesWith(rhs); + } else if (rhs.IsUnsignedImmediate(1)) { + inst.ReplaceUsesWith(lhs); + } +} + // 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); @@ -174,6 +207,10 @@ void ConstantPropagation(IR::Block& block) { } break; } + case IR::Opcode::Mul32: + case IR::Opcode::Mul64: + FoldMultiply(inst, opcode == IR::Opcode::Mul32); + break; case IR::Opcode::And32: case IR::Opcode::And64: FoldAND(inst, opcode == IR::Opcode::And32); From 7ad6981437fbf78ae25ed15b2fc490ed2ad5803e Mon Sep 17 00:00:00 2001 From: Lioncash Date: Sun, 7 Oct 2018 22:11:47 -0400 Subject: [PATCH 2/2] constant_propagation_pass: deduplicate common 32/64 bit checking for results in folding functions It's common for an folding operation to apply to both the 32-bit and 64-bit variant of the same opcode, which leads to checking which kind of result we need to store the value as. This moves it to its own function, so that we don't need to duplicate it in various functions. --- src/ir_opt/constant_propagation_pass.cpp | 63 ++++++++---------------- 1 file changed, 21 insertions(+), 42 deletions(-) diff --git a/src/ir_opt/constant_propagation_pass.cpp b/src/ir_opt/constant_propagation_pass.cpp index c18f31cd..40d2b90a 100644 --- a/src/ir_opt/constant_propagation_pass.cpp +++ b/src/ir_opt/constant_propagation_pass.cpp @@ -13,6 +13,16 @@ namespace Dynarmic::Optimization { namespace { +// Tiny helper to avoid the need to store based off the opcode +// bit size all over the place within folding functions. +void ReplaceUsesWith(IR::Inst& inst, bool is_32_bit, u64 value) { + if (is_32_bit) { + inst.ReplaceUsesWith(IR::Value{static_cast(value)}); + } else { + inst.ReplaceUsesWith(IR::Value{value}); + } +} + // Folds AND operations based on the following: // // 1. imm_x & imm_y -> result @@ -30,18 +40,9 @@ void FoldAND(IR::Inst& inst, bool is_32_bit) { 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}); - } + ReplaceUsesWith(inst, is_32_bit, result); } else if (lhs.IsZero() || rhs.IsZero()) { - if (is_32_bit) { - inst.ReplaceUsesWith(IR::Value{u32{0}}); - } else { - inst.ReplaceUsesWith(IR::Value{u64{0}}); - } + ReplaceUsesWith(inst, is_32_bit, 0); } else if (is_lhs_immediate && lhs.HasAllBitsSet()) { inst.ReplaceUsesWith(rhs); } else if (is_rhs_immediate && rhs.HasAllBitsSet()) { @@ -61,12 +62,7 @@ void FoldEOR(IR::Inst& inst, bool is_32_bit) { if (lhs.IsImmediate() && rhs.IsImmediate()) { const u64 result = lhs.GetImmediateAsU64() ^ rhs.GetImmediateAsU64(); - - if (is_32_bit) { - inst.ReplaceUsesWith(IR::Value{static_cast(result)}); - } else { - inst.ReplaceUsesWith(IR::Value{result}); - } + ReplaceUsesWith(inst, is_32_bit, result); } else if (lhs.IsZero()) { inst.ReplaceUsesWith(rhs); } else if (rhs.IsZero()) { @@ -88,18 +84,9 @@ void FoldMultiply(IR::Inst& inst, bool is_32_bit) { if (lhs.IsImmediate() && rhs.IsImmediate()) { const u64 result = lhs.GetImmediateAsU64() * rhs.GetImmediateAsU64(); - - if (is_32_bit) { - inst.ReplaceUsesWith(IR::Value{static_cast(result)}); - } else { - inst.ReplaceUsesWith(IR::Value{result}); - } + ReplaceUsesWith(inst, is_32_bit, result); } else if (lhs.IsZero() || rhs.IsZero()) { - if (is_32_bit) { - inst.ReplaceUsesWith(IR::Value{u32{0}}); - } else { - inst.ReplaceUsesWith(IR::Value{u64{0}}); - } + ReplaceUsesWith(inst, is_32_bit, 0); } else if (lhs.IsUnsignedImmediate(1)) { inst.ReplaceUsesWith(rhs); } else if (rhs.IsUnsignedImmediate(1)) { @@ -111,15 +98,12 @@ void FoldMultiply(IR::Inst& inst, bool is_32_bit) { 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}); - } + if (!operand.IsImmediate()) { + return; } + + const u64 result = ~operand.GetImmediateAsU64(); + ReplaceUsesWith(inst, is_32_bit, result); } // Folds OR operations based on the following: @@ -134,12 +118,7 @@ void FoldOR(IR::Inst& inst, bool is_32_bit) { if (lhs.IsImmediate() && rhs.IsImmediate()) { const u64 result = lhs.GetImmediateAsU64() | rhs.GetImmediateAsU64(); - - if (is_32_bit) { - inst.ReplaceUsesWith(IR::Value{static_cast(result)}); - } else { - inst.ReplaceUsesWith(IR::Value{result}); - } + ReplaceUsesWith(inst, is_32_bit, result); } else if (lhs.IsZero()) { inst.ReplaceUsesWith(rhs); } else if (rhs.IsZero()) {