value: Move ImmediateToU64() to be a part of Value's interface

This'll make it slightly nicer to do basic constant folding for 32-bit
and 64-bit variants of the same IR opcode type. By that, I mean it's
possible to inspect immediate values without a bunch of conditional
checks beforehand to verify that it's possible to call GetU32() or
GetU64, etc.
This commit is contained in:
Lioncash 2018-09-28 14:46:38 -04:00 committed by MerryMage
parent ca603c1215
commit d69fceec55
3 changed files with 38 additions and 29 deletions

View file

@ -26,23 +26,6 @@ namespace Dynarmic::BackendX64 {
} \ } \
}() }()
static u64 ImmediateToU64(const IR::Value& imm) {
switch (imm.GetType()) {
case IR::Type::U1:
return u64(imm.GetU1());
case IR::Type::U8:
return u64(imm.GetU8());
case IR::Type::U16:
return u64(imm.GetU16());
case IR::Type::U32:
return u64(imm.GetU32());
case IR::Type::U64:
return u64(imm.GetU64());
default:
ASSERT_MSG(false, "This should never happen.");
}
}
static bool CanExchange(HostLoc a, HostLoc b) { static bool CanExchange(HostLoc a, HostLoc b) {
return HostLocIsGPR(a) && HostLocIsGPR(b); return HostLocIsGPR(a) && HostLocIsGPR(b);
} }
@ -179,14 +162,14 @@ bool Argument::IsVoid() const {
bool Argument::FitsInImmediateU32() const { bool Argument::FitsInImmediateU32() const {
if (!IsImmediate()) if (!IsImmediate())
return false; return false;
u64 imm = ImmediateToU64(value); const u64 imm = value.GetImmediateAsU64();
return imm < 0x100000000; return imm < 0x100000000;
} }
bool Argument::FitsInImmediateS32() const { bool Argument::FitsInImmediateS32() const {
if (!IsImmediate()) if (!IsImmediate())
return false; return false;
s64 imm = static_cast<s64>(ImmediateToU64(value)); const s64 imm = static_cast<s64>(value.GetImmediateAsU64());
return -s64(0x80000000) <= imm && imm <= s64(0x7FFFFFFF); return -s64(0x80000000) <= imm && imm <= s64(0x7FFFFFFF);
} }
@ -195,31 +178,30 @@ bool Argument::GetImmediateU1() const {
} }
u8 Argument::GetImmediateU8() const { u8 Argument::GetImmediateU8() const {
u64 imm = ImmediateToU64(value); const u64 imm = value.GetImmediateAsU64();
ASSERT(imm < 0x100); ASSERT(imm < 0x100);
return u8(imm); return u8(imm);
} }
u16 Argument::GetImmediateU16() const { u16 Argument::GetImmediateU16() const {
u64 imm = ImmediateToU64(value); const u64 imm = value.GetImmediateAsU64();
ASSERT(imm < 0x10000); ASSERT(imm < 0x10000);
return u16(imm); return u16(imm);
} }
u32 Argument::GetImmediateU32() const { u32 Argument::GetImmediateU32() const {
u64 imm = ImmediateToU64(value); const u64 imm = value.GetImmediateAsU64();
ASSERT(imm < 0x100000000); ASSERT(imm < 0x100000000);
return u32(imm); return u32(imm);
} }
u64 Argument::GetImmediateS32() const { u64 Argument::GetImmediateS32() const {
ASSERT(FitsInImmediateS32()); ASSERT(FitsInImmediateS32());
u64 imm = ImmediateToU64(value); return value.GetImmediateAsU64();
return imm;
} }
u64 Argument::GetImmediateU64() const { u64 Argument::GetImmediateU64() const {
return ImmediateToU64(value); return value.GetImmediateAsU64();
} }
IR::Cond Argument::GetImmediateCond() const { IR::Cond Argument::GetImmediateCond() const {
@ -502,8 +484,8 @@ HostLoc RegAlloc::LoadImmediate(IR::Value imm, HostLoc host_loc) {
ASSERT_MSG(imm.IsImmediate(), "imm is not an immediate"); ASSERT_MSG(imm.IsImmediate(), "imm is not an immediate");
if (HostLocIsGPR(host_loc)) { if (HostLocIsGPR(host_loc)) {
Xbyak::Reg64 reg = HostLocToReg64(host_loc); const Xbyak::Reg64 reg = HostLocToReg64(host_loc);
u64 imm_value = ImmediateToU64(imm); const u64 imm_value = imm.GetImmediateAsU64();
if (imm_value == 0) if (imm_value == 0)
code.xor_(reg.cvt32(), reg.cvt32()); code.xor_(reg.cvt32(), reg.cvt32());
else else
@ -512,8 +494,8 @@ HostLoc RegAlloc::LoadImmediate(IR::Value imm, HostLoc host_loc) {
} }
if (HostLocIsXMM(host_loc)) { if (HostLocIsXMM(host_loc)) {
Xbyak::Xmm reg = HostLocToXmm(host_loc); const Xbyak::Xmm reg = HostLocToXmm(host_loc);
u64 imm_value = ImmediateToU64(imm); const u64 imm_value = imm.GetImmediateAsU64();
if (imm_value == 0) if (imm_value == 0)
MAYBE_AVX(xorps, reg, reg); MAYBE_AVX(xorps, reg, reg);
else else

View file

@ -155,4 +155,23 @@ Cond Value::GetCond() const {
return inner.imm_cond; return inner.imm_cond;
} }
u64 Value::GetImmediateAsU64() const {
ASSERT(IsImmediate());
switch (GetType()) {
case IR::Type::U1:
return u64(GetU1());
case IR::Type::U8:
return u64(GetU8());
case IR::Type::U16:
return u64(GetU16());
case IR::Type::U32:
return u64(GetU32());
case IR::Type::U64:
return u64(GetU64());
default:
ASSERT_MSG(false, "GetImmediateAsU64 called on an incompatible Value type.");
}
}
} // namespace Dynarmic::IR } // namespace Dynarmic::IR

View file

@ -66,6 +66,14 @@ public:
CoprocessorInfo GetCoprocInfo() const; CoprocessorInfo GetCoprocInfo() const;
Cond GetCond() const; Cond GetCond() const;
/**
* Retrieves the immediate of a Value instance.
*
* @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;
private: private:
Type type; Type type;