diff --git a/src/frontend/ir/value.cpp b/src/frontend/ir/value.cpp index a7ef2e65..6d5dbecb 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()); @@ -174,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()); @@ -194,4 +222,8 @@ bool Value::HasAllBitsSet() const { } } +bool Value::IsZero() const { + return IsUnsignedImmediate(0); +} + } // namespace Dynarmic::IR diff --git a/src/frontend/ir/value.h b/src/frontend/ir/value.h index 80f5970c..5beaf9e8 100644 --- a/src/frontend/ir/value.h +++ b/src/frontend/ir/value.h @@ -67,13 +67,43 @@ 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. */ 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. * @@ -82,6 +112,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); } }