From 4a3c064b156c6bfe09b239484ce8521fb64e3783 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Thu, 4 Oct 2018 04:52:44 -0400 Subject: [PATCH 1/3] ir/value: Add an IsZero() member function to Value's interface By far, one of the most common things to check for is whether or not a value is zero, as it typically allows folding away unnecesary operations (other close contenders that can help with eliding operations are 1 and -1). So instead of requiring a check for an immediate and then actually retrieving the integral value and checking it, we can wrap it within a function to make it more convenient. --- src/frontend/ir/value.cpp | 4 ++++ src/frontend/ir/value.h | 9 +++++++++ src/ir_opt/constant_propagation_pass.cpp | 20 +++++++------------- 3 files changed, 20 insertions(+), 13 deletions(-) diff --git a/src/frontend/ir/value.cpp b/src/frontend/ir/value.cpp index a7ef2e65..5c3eb4b5 100644 --- a/src/frontend/ir/value.cpp +++ b/src/frontend/ir/value.cpp @@ -194,4 +194,8 @@ bool Value::HasAllBitsSet() const { } } +bool Value::IsZero() const { + return IsImmediate() && GetImmediateAsU64() == 0; +} + } // namespace Dynarmic::IR diff --git a/src/frontend/ir/value.h b/src/frontend/ir/value.h index 80f5970c..a8496d7b 100644 --- a/src/frontend/ir/value.h +++ b/src/frontend/ir/value.h @@ -82,6 +82,15 @@ public: */ bool HasAllBitsSet() const; + /** + * Whether or not the current value contains a representation of zero. + * + * Note that this function will always return false if the contained + * value is not a a constant value. In other words, if IsImmediate() + * would return false on an instance, then so will this function. + */ + bool IsZero() const; + private: Type type; diff --git a/src/ir_opt/constant_propagation_pass.cpp b/src/ir_opt/constant_propagation_pass.cpp index 4d323bf3..aec32546 100644 --- a/src/ir_opt/constant_propagation_pass.cpp +++ b/src/ir_opt/constant_propagation_pass.cpp @@ -36,7 +36,7 @@ void FoldAND(IR::Inst& inst, bool is_32_bit) { } else { inst.ReplaceUsesWith(IR::Value{result}); } - } else if ((is_lhs_immediate && lhs.GetImmediateAsU64() == 0) || (is_rhs_immediate && rhs.GetImmediateAsU64() == 0)) { + } else if (lhs.IsZero() || rhs.IsZero()) { if (is_32_bit) { inst.ReplaceUsesWith(IR::Value{u32{0}}); } else { @@ -59,10 +59,7 @@ 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) { + if (lhs.IsImmediate() && rhs.IsImmediate()) { const u64 result = lhs.GetImmediateAsU64() ^ rhs.GetImmediateAsU64(); if (is_32_bit) { @@ -70,9 +67,9 @@ void FoldEOR(IR::Inst& inst, bool is_32_bit) { } else { inst.ReplaceUsesWith(IR::Value{result}); } - } else if (is_lhs_immediate && lhs.GetImmediateAsU64() == 0) { + } else if (lhs.IsZero()) { inst.ReplaceUsesWith(rhs); - } else if (is_rhs_immediate && rhs.GetImmediateAsU64() == 0) { + } else if (rhs.IsZero()) { inst.ReplaceUsesWith(lhs); } } @@ -102,10 +99,7 @@ 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) { + if (lhs.IsImmediate() && rhs.IsImmediate()) { const u64 result = lhs.GetImmediateAsU64() | rhs.GetImmediateAsU64(); if (is_32_bit) { @@ -113,9 +107,9 @@ void FoldOR(IR::Inst& inst, bool is_32_bit) { } else { inst.ReplaceUsesWith(IR::Value{result}); } - } else if (is_lhs_immediate && lhs.GetImmediateAsU64() == 0) { + } else if (lhs.IsZero()) { inst.ReplaceUsesWith(rhs); - } else if (is_rhs_immediate && rhs.GetImmediateAsU64() == 0) { + } else if (rhs.IsZero()) { inst.ReplaceUsesWith(lhs); } } From e3258e852546e3f119e54c5f77b1583498c280f2 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Thu, 4 Oct 2018 05:10:08 -0400 Subject: [PATCH 2/3] ir/value: Add a GetImmediateAsS64() function Provides a signed analogue to GetImmediateAsU64() for consistency with both integral classes when it comes to signed/unsigned.. --- src/frontend/ir/value.cpp | 20 ++++++++++++++++++++ src/frontend/ir/value.h | 10 +++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/frontend/ir/value.cpp b/src/frontend/ir/value.cpp index 5c3eb4b5..c3742227 100644 --- a/src/frontend/ir/value.cpp +++ b/src/frontend/ir/value.cpp @@ -5,6 +5,7 @@ */ #include "common/assert.h" +#include "common/bit_util.h" #include "frontend/ir/microinstruction.h" #include "frontend/ir/opcodes.h" #include "frontend/ir/type.h" @@ -155,6 +156,25 @@ Cond Value::GetCond() const { return inner.imm_cond; } +s64 Value::GetImmediateAsS64() const { + ASSERT(IsImmediate()); + + switch (GetType()) { + case IR::Type::U1: + return s64(GetU1()); + case IR::Type::U8: + return s64(Common::SignExtend<8, u64>(GetU8())); + case IR::Type::U16: + return s64(Common::SignExtend<16, u64>(GetU16())); + case IR::Type::U32: + return s64(Common::SignExtend<32, u64>(GetU32())); + case IR::Type::U64: + return s64(GetU64()); + default: + ASSERT_MSG(false, "GetImmediateAsS64 called on an incompatible Value type."); + } +} + u64 Value::GetImmediateAsU64() const { ASSERT(IsImmediate()); diff --git a/src/frontend/ir/value.h b/src/frontend/ir/value.h index a8496d7b..cd3bbf07 100644 --- a/src/frontend/ir/value.h +++ b/src/frontend/ir/value.h @@ -67,7 +67,15 @@ public: Cond GetCond() const; /** - * Retrieves the immediate of a Value instance. + * Retrieves the immediate of a Value instance as a signed 64-bit value. + * + * @pre The value contains either a U1, U8, U16, U32, or U64 value. + * Breaking this precondition will cause an assertion to be invoked. + */ + s64 GetImmediateAsS64() const; + + /** + * Retrieves the immediate of a Value instance as an unsigned 64-bit value. * * @pre The value contains either a U1, U8, U16, U32, or U64 value. * Breaking this precondition will cause an assertion to be invoked. From 0583d401e3e9a77aee3b841f954d494c0a96faaf Mon Sep 17 00:00:00 2001 From: Lioncash Date: Thu, 4 Oct 2018 05:18:22 -0400 Subject: [PATCH 3/3] ir/value: Add IsSignedImmediate() and IsUnsignedImmediate() functions to Value's interface This allows testing against arbitrary values while also simultaneously eliminating the need to check IsImmediate() all the time in expressions. --- src/frontend/ir/value.cpp | 10 +++++++++- src/frontend/ir/value.h | 22 ++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/frontend/ir/value.cpp b/src/frontend/ir/value.cpp index c3742227..6d5dbecb 100644 --- a/src/frontend/ir/value.cpp +++ b/src/frontend/ir/value.cpp @@ -194,6 +194,14 @@ u64 Value::GetImmediateAsU64() const { } } +bool Value::IsSignedImmediate(s64 value) const { + return IsImmediate() && GetImmediateAsS64() == value; +} + +bool Value::IsUnsignedImmediate(u64 value) const { + return IsImmediate() && GetImmediateAsU64() == value; +} + bool Value::HasAllBitsSet() const { ASSERT(IsImmediate()); @@ -215,7 +223,7 @@ bool Value::HasAllBitsSet() const { } bool Value::IsZero() const { - return IsImmediate() && GetImmediateAsU64() == 0; + return IsUnsignedImmediate(0); } } // namespace Dynarmic::IR diff --git a/src/frontend/ir/value.h b/src/frontend/ir/value.h index cd3bbf07..5beaf9e8 100644 --- a/src/frontend/ir/value.h +++ b/src/frontend/ir/value.h @@ -82,6 +82,28 @@ public: */ u64 GetImmediateAsU64() const; + /** + * Determines whether or not the contained value matches the provided signed one. + * + * Note that this function will always return false if the contained + * value is not a a constant value. In other words, if IsImmediate() + * would return false on an instance, then so will this function. + * + * @param value The value to check against the contained value. + */ + bool IsSignedImmediate(s64 value) const; + + /** + * Determines whether or not the contained value matches the provided unsigned one. + * + * Note that this function will always return false if the contained + * value is not a a constant value. In other words, if IsImmediate() + * would return false on an instance, then so will this function. + * + * @param value The value to check against the contained value. + */ + bool IsUnsignedImmediate(u64 value) const; + /** * Determines whether or not the contained constant value has all bits set. *