mirror of
https://git.suyu.dev/suyu/dynarmic.git
synced 2026-03-06 10:32:58 +00:00
A64: Implement addsub instructions
This commit is contained in:
@@ -49,11 +49,17 @@ ResultAndCarry<U32> IREmitter::MostSignificantWord(const U64& value) {
|
||||
return {result, carry_out};
|
||||
}
|
||||
|
||||
U16 IREmitter::LeastSignificantHalf(const U32& value) {
|
||||
U16 IREmitter::LeastSignificantHalf(U32U64 value) {
|
||||
if (value.GetType() == Type::U64) {
|
||||
value = LeastSignificantWord(value);
|
||||
}
|
||||
return Inst<U16>(Opcode::LeastSignificantHalf, value);
|
||||
}
|
||||
|
||||
U8 IREmitter::LeastSignificantByte(const U32& value) {
|
||||
U8 IREmitter::LeastSignificantByte(U32U64 value) {
|
||||
if (value.GetType() == Type::U64) {
|
||||
value = LeastSignificantWord(value);
|
||||
}
|
||||
return Inst<U8>(Opcode::LeastSignificantByte, value);
|
||||
}
|
||||
|
||||
@@ -69,6 +75,10 @@ U1 IREmitter::IsZero64(const U64& value) {
|
||||
return Inst<U1>(Opcode::IsZero64, value);
|
||||
}
|
||||
|
||||
NZCV IREmitter::NZCVFrom(const Value& value) {
|
||||
return Inst<NZCV>(Opcode::GetNZCVFromOp, value);
|
||||
}
|
||||
|
||||
ResultAndCarry<U32> IREmitter::LogicalShiftLeft(const U32& value_in, const U8& shift_amount, const U1& carry_in) {
|
||||
auto result = Inst<U32>(Opcode::LogicalShiftLeft32, value_in, shift_amount, carry_in);
|
||||
auto carry_out = Inst<U1>(Opcode::GetCarryFromOp, result);
|
||||
@@ -135,48 +145,75 @@ U32U64 IREmitter::RotateRight(const U32U64& value_in, const U8& shift_amount) {
|
||||
}
|
||||
}
|
||||
|
||||
ResultAndCarryAndOverflow<U32> IREmitter::AddWithCarry(const Value& a, const Value& b, const U1& carry_in) {
|
||||
auto result = Inst<U32>(Opcode::AddWithCarry, a, b, carry_in);
|
||||
ResultAndCarryAndOverflow<U32> IREmitter::AddWithCarry(const U32& a, const U32& b, const U1& carry_in) {
|
||||
auto result = Inst<U32>(Opcode::Add32, a, b, carry_in);
|
||||
auto carry_out = Inst<U1>(Opcode::GetCarryFromOp, result);
|
||||
auto overflow = Inst<U1>(Opcode::GetOverflowFromOp, result);
|
||||
return {result, carry_out, overflow};
|
||||
}
|
||||
|
||||
U32U64 IREmitter::AddWithCarry(const U32U64& a, const U32U64& b, const U1& carry_in) {
|
||||
ASSERT(a.GetType() == b.GetType());
|
||||
if (a.GetType() == Type::U32) {
|
||||
return Inst<U32>(Opcode::Add32, a, b, carry_in);
|
||||
} else {
|
||||
return Inst<U64>(Opcode::Add64, a, b, carry_in);
|
||||
}
|
||||
}
|
||||
|
||||
U32 IREmitter::Add(const U32& a, const U32& b) {
|
||||
return Inst<U32>(Opcode::AddWithCarry, a, b, Imm1(0));
|
||||
return Inst<U32>(Opcode::Add32, a, b, Imm1(0));
|
||||
}
|
||||
|
||||
U64 IREmitter::Add(const U64& a, const U64& b) {
|
||||
return Inst<U64>(Opcode::Add64, a, b);
|
||||
return Inst<U64>(Opcode::Add64, a, b, Imm1(0));
|
||||
}
|
||||
|
||||
U32U64 IREmitter::Add(const U32U64& a, const U32U64& b) {
|
||||
ASSERT(a.GetType() == b.GetType());
|
||||
if (a.GetType() == Type::U32) {
|
||||
return Inst<U32>(Opcode::AddWithCarry, a, b, Imm1(0));
|
||||
return Inst<U32>(Opcode::Add32, a, b, Imm1(0));
|
||||
} else {
|
||||
return Inst<U64>(Opcode::Add64, a, b);
|
||||
return Inst<U64>(Opcode::Add64, a, b, Imm1(0));
|
||||
}
|
||||
}
|
||||
|
||||
ResultAndCarryAndOverflow<U32> IREmitter::SubWithCarry(const U32& a, const U32& b, const U1& carry_in) {
|
||||
// This is equivalent to AddWithCarry(a, Not(b), carry_in).
|
||||
auto result = Inst<U32>(Opcode::SubWithCarry, a, b, carry_in);
|
||||
auto result = Inst<U32>(Opcode::Sub32, a, b, carry_in);
|
||||
auto carry_out = Inst<U1>(Opcode::GetCarryFromOp, result);
|
||||
auto overflow = Inst<U1>(Opcode::GetOverflowFromOp, result);
|
||||
return {result, carry_out, overflow};
|
||||
}
|
||||
|
||||
U32U64 IREmitter::SubWithCarry(const U32U64& a, const U32U64& b, const U1& carry_in) {
|
||||
ASSERT(a.GetType() == b.GetType());
|
||||
if (a.GetType() == Type::U32) {
|
||||
return Inst<U32>(Opcode::Sub32, a, b, carry_in);
|
||||
} else {
|
||||
return Inst<U64>(Opcode::Sub64, a, b, carry_in);
|
||||
}
|
||||
}
|
||||
|
||||
U32 IREmitter::Sub(const U32& a, const U32& b) {
|
||||
return Inst<U32>(Opcode::SubWithCarry, a, b, Imm1(1));
|
||||
return Inst<U32>(Opcode::Sub32, a, b, Imm1(1));
|
||||
}
|
||||
|
||||
U64 IREmitter::Sub(const U64& a, const U64& b) {
|
||||
return Inst<U64>(Opcode::Sub64, a, b);
|
||||
return Inst<U64>(Opcode::Sub64, a, b, Imm1(1));
|
||||
}
|
||||
|
||||
U32U64 IREmitter::Sub(const U32U64& a, const U32U64& b) {
|
||||
ASSERT(a.GetType() == b.GetType());
|
||||
if (a.GetType() == Type::U32) {
|
||||
return Inst<U32>(Opcode::Sub32, a, b, Imm1(1));
|
||||
} else {
|
||||
return Inst<U64>(Opcode::Sub64, a, b, Imm1(1));
|
||||
}
|
||||
}
|
||||
|
||||
U32 IREmitter::Mul(const U32& a, const U32& b) {
|
||||
return Inst<U32>(Opcode::Mul, a, b);
|
||||
return Inst<U32>(Opcode::Mul32, a, b);
|
||||
}
|
||||
|
||||
U64 IREmitter::Mul(const U64& a, const U64& b) {
|
||||
@@ -199,6 +236,38 @@ U32 IREmitter::Not(const U32& a) {
|
||||
return Inst<U32>(Opcode::Not, a);
|
||||
}
|
||||
|
||||
U64 IREmitter::SignExtendToLong(const UAny& a) {
|
||||
switch (a.GetType()) {
|
||||
case Type::U8:
|
||||
return Inst<U64>(Opcode::SignExtendByteToLong, a);
|
||||
case Type::U16:
|
||||
return Inst<U64>(Opcode::SignExtendHalfToLong, a);
|
||||
case Type::U32:
|
||||
return Inst<U64>(Opcode::SignExtendWordToLong, a);
|
||||
case Type::U64:
|
||||
return U64(a);
|
||||
default:
|
||||
ASSERT_MSG(false, "Unreachable");
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
U32 IREmitter::SignExtendToWord(const UAny& a) {
|
||||
switch (a.GetType()) {
|
||||
case Type::U8:
|
||||
return Inst<U32>(Opcode::SignExtendByteToWord, a);
|
||||
case Type::U16:
|
||||
return Inst<U32>(Opcode::SignExtendHalfToWord, a);
|
||||
case Type::U32:
|
||||
return U32(a);
|
||||
case Type::U64:
|
||||
return Inst<U32>(Opcode::LeastSignificantWord, a);
|
||||
default:
|
||||
ASSERT_MSG(false, "Unreachable");
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
U64 IREmitter::SignExtendWordToLong(const U32& a) {
|
||||
return Inst<U64>(Opcode::SignExtendWordToLong, a);
|
||||
}
|
||||
@@ -211,6 +280,38 @@ U32 IREmitter::SignExtendByteToWord(const U8& a) {
|
||||
return Inst<U32>(Opcode::SignExtendByteToWord, a);
|
||||
}
|
||||
|
||||
U64 IREmitter::ZeroExtendToLong(const UAny& a) {
|
||||
switch (a.GetType()) {
|
||||
case Type::U8:
|
||||
return Inst<U64>(Opcode::ZeroExtendByteToLong, a);
|
||||
case Type::U16:
|
||||
return Inst<U64>(Opcode::ZeroExtendHalfToLong, a);
|
||||
case Type::U32:
|
||||
return Inst<U64>(Opcode::ZeroExtendWordToLong, a);
|
||||
case Type::U64:
|
||||
return U64(a);
|
||||
default:
|
||||
ASSERT_MSG(false, "Unreachable");
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
U32 IREmitter::ZeroExtendToWord(const UAny& a) {
|
||||
switch (a.GetType()) {
|
||||
case Type::U8:
|
||||
return Inst<U32>(Opcode::ZeroExtendByteToWord, a);
|
||||
case Type::U16:
|
||||
return Inst<U32>(Opcode::ZeroExtendHalfToWord, a);
|
||||
case Type::U32:
|
||||
return U32(a);
|
||||
case Type::U64:
|
||||
return Inst<U32>(Opcode::LeastSignificantWord, a);
|
||||
default:
|
||||
ASSERT_MSG(false, "Unreachable");
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
U64 IREmitter::ZeroExtendWordToLong(const U32& a) {
|
||||
return Inst<U64>(Opcode::ZeroExtendWordToLong, a);
|
||||
}
|
||||
|
||||
@@ -76,12 +76,15 @@ public:
|
||||
U64 Pack2x32To1x64(const U32& lo, const U32& hi);
|
||||
U32 LeastSignificantWord(const U64& value);
|
||||
ResultAndCarry<U32> MostSignificantWord(const U64& value);
|
||||
U16 LeastSignificantHalf(const U32& value);
|
||||
U8 LeastSignificantByte(const U32& value);
|
||||
U16 LeastSignificantHalf(U32U64 value);
|
||||
U8 LeastSignificantByte(U32U64 value);
|
||||
U1 MostSignificantBit(const U32& value);
|
||||
U1 IsZero(const U32& value);
|
||||
U1 IsZero64(const U64& value);
|
||||
|
||||
// This pseudo-instruction may only be added to instructions that support it.
|
||||
NZCV NZCVFrom(const Value& value);
|
||||
|
||||
ResultAndCarry<U32> LogicalShiftLeft(const U32& value_in, const U8& shift_amount, const U1& carry_in);
|
||||
ResultAndCarry<U32> LogicalShiftRight(const U32& value_in, const U8& shift_amount, const U1& carry_in);
|
||||
ResultAndCarry<U32> ArithmeticShiftRight(const U32& value_in, const U8& shift_amount, const U1& carry_in);
|
||||
@@ -92,25 +95,32 @@ public:
|
||||
U32U64 ArithmeticShiftRight(const U32U64& value_in, const U8& shift_amount);
|
||||
U32U64 RotateRight(const U32U64& value_in, const U8& shift_amount);
|
||||
ResultAndCarry<U32> RotateRightExtended(const U32& value_in, const U1& carry_in);
|
||||
ResultAndCarryAndOverflow<U32> AddWithCarry(const Value& a, const Value& b, const U1& carry_in);
|
||||
ResultAndCarryAndOverflow<U32> AddWithCarry(const U32& a, const U32& b, const U1& carry_in);
|
||||
ResultAndCarryAndOverflow<U32> SubWithCarry(const U32& a, const U32& b, const U1& carry_in);
|
||||
U32U64 AddWithCarry(const U32U64& a, const U32U64& b, const U1& carry_in);
|
||||
U32U64 SubWithCarry(const U32U64& a, const U32U64& b, const U1& carry_in);
|
||||
U32 Add(const U32& a, const U32& b);
|
||||
U64 Add(const U64& a, const U64& b);
|
||||
U32U64 Add(const U32U64& a, const U32U64& b);
|
||||
ResultAndCarryAndOverflow<U32> SubWithCarry(const U32& a, const U32& b, const U1& carry_in);
|
||||
U32 Sub(const U32& a, const U32& b);
|
||||
U64 Sub(const U64& a, const U64& b);
|
||||
U32U64 Sub(const U32U64& a, const U32U64& b);
|
||||
U32 Mul(const U32& a, const U32& b);
|
||||
U64 Mul(const U64& a, const U64& b);
|
||||
U32 And(const U32& a, const U32& b);
|
||||
U32 Eor(const U32& a, const U32& b);
|
||||
U32 Or(const U32& a, const U32& b);
|
||||
U32 Not(const U32& a);
|
||||
U64 SignExtendWordToLong(const U32& a);
|
||||
U32 SignExtendHalfToWord(const U16& a);
|
||||
U32 SignExtendToWord(const UAny& a);
|
||||
U64 SignExtendToLong(const UAny& a);
|
||||
U32 SignExtendByteToWord(const U8& a);
|
||||
U64 ZeroExtendWordToLong(const U32& a);
|
||||
U32 ZeroExtendHalfToWord(const U16& a);
|
||||
U32 SignExtendHalfToWord(const U16& a);
|
||||
U64 SignExtendWordToLong(const U32& a);
|
||||
U32 ZeroExtendToWord(const UAny& a);
|
||||
U64 ZeroExtendToLong(const UAny& a);
|
||||
U32 ZeroExtendByteToWord(const U8& a);
|
||||
U32 ZeroExtendHalfToWord(const U16& a);
|
||||
U64 ZeroExtendWordToLong(const U32& a);
|
||||
U32 ByteReverseWord(const U32& a);
|
||||
U16 ByteReverseHalf(const U16& a);
|
||||
U64 ByteReverseDual(const U64& a);
|
||||
|
||||
@@ -138,6 +138,7 @@ bool Inst::ReadsFromCoreRegister() const {
|
||||
case Opcode::A32GetExtendedRegister64:
|
||||
case Opcode::A64GetW:
|
||||
case Opcode::A64GetX:
|
||||
case Opcode::A64GetSP:
|
||||
return true;
|
||||
|
||||
default:
|
||||
@@ -153,6 +154,7 @@ bool Inst::WritesToCoreRegister() const {
|
||||
case Opcode::A32BXWritePC:
|
||||
case Opcode::A64SetW:
|
||||
case Opcode::A64SetX:
|
||||
case Opcode::A64SetSP:
|
||||
return true;
|
||||
|
||||
default:
|
||||
@@ -252,26 +254,55 @@ bool Inst::MayHaveSideEffects() const {
|
||||
IsCoprocessorInstruction();
|
||||
}
|
||||
|
||||
bool Inst::IsAPseudoOperation() const {
|
||||
switch (op) {
|
||||
case Opcode::GetCarryFromOp:
|
||||
case Opcode::GetOverflowFromOp:
|
||||
case Opcode::GetGEFromOp:
|
||||
case Opcode::GetNZCVFromOp:
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool Inst::MayGetNZCVFromOp() const {
|
||||
switch (op) {
|
||||
case Opcode::Add32:
|
||||
case Opcode::Add64:
|
||||
case Opcode::Sub32:
|
||||
case Opcode::Sub64:
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool Inst::AreAllArgsImmediates() const {
|
||||
return std::all_of(args.begin(), args.begin() + NumArgs(), [](const auto& value){ return value.IsImmediate(); });
|
||||
}
|
||||
|
||||
bool Inst::HasAssociatedPseudoOperation() const {
|
||||
return carry_inst || overflow_inst || ge_inst;
|
||||
return carry_inst || overflow_inst || ge_inst || nzcv_inst;
|
||||
}
|
||||
|
||||
Inst* Inst::GetAssociatedPseudoOperation(Opcode opcode) {
|
||||
// This is faster than doing a search through the block.
|
||||
switch (opcode) {
|
||||
case IR::Opcode::GetCarryFromOp:
|
||||
case Opcode::GetCarryFromOp:
|
||||
ASSERT(!carry_inst || carry_inst->GetOpcode() == Opcode::GetCarryFromOp);
|
||||
return carry_inst;
|
||||
case IR::Opcode::GetOverflowFromOp:
|
||||
case Opcode::GetOverflowFromOp:
|
||||
ASSERT(!overflow_inst || overflow_inst->GetOpcode() == Opcode::GetOverflowFromOp);
|
||||
return overflow_inst;
|
||||
case IR::Opcode::GetGEFromOp:
|
||||
case Opcode::GetGEFromOp:
|
||||
ASSERT(!ge_inst || ge_inst->GetOpcode() == Opcode::GetGEFromOp);
|
||||
return ge_inst;
|
||||
case Opcode::GetNZCVFromOp:
|
||||
ASSERT(!nzcv_inst || nzcv_inst->GetOpcode() == Opcode::GetNZCVFromOp);
|
||||
return nzcv_inst;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -345,6 +376,11 @@ void Inst::Use(const Value& value) {
|
||||
ASSERT_MSG(!value.GetInst()->ge_inst, "Only one of each type of pseudo-op allowed");
|
||||
value.GetInst()->ge_inst = this;
|
||||
break;
|
||||
case Opcode::GetNZCVFromOp:
|
||||
ASSERT_MSG(!value.GetInst()->nzcv_inst, "Only one of each type of pseudo-op allowed");
|
||||
ASSERT_MSG(MayGetNZCVFromOp(), "This instruction doesn't support the GetNZCVFromOp pseduo-op");
|
||||
value.GetInst()->nzcv_inst = this;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -366,6 +402,10 @@ void Inst::UndoUse(const Value& value) {
|
||||
ASSERT(value.GetInst()->ge_inst->GetOpcode() == Opcode::GetGEFromOp);
|
||||
value.GetInst()->ge_inst = nullptr;
|
||||
break;
|
||||
case Opcode::GetNZCVFromOp:
|
||||
ASSERT(value.GetInst()->nzcv_inst->GetOpcode() == Opcode::GetNZCVFromOp);
|
||||
value.GetInst()->nzcv_inst = nullptr;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -76,6 +76,13 @@ public:
|
||||
/// Determines whether or not this instruction may have side-effects.
|
||||
bool MayHaveSideEffects() const;
|
||||
|
||||
/// Determines whether or not this instruction is a pseduo-instruction.
|
||||
/// Pseudo-instructions depend on their parent instructions for their semantics.
|
||||
bool IsAPseudoOperation() const;
|
||||
|
||||
/// Determins whether or not this instruction supports the GetNZCVFromOp pseudo-operation.
|
||||
bool MayGetNZCVFromOp() const;
|
||||
|
||||
/// Determines if all arguments of this instruction are immediates.
|
||||
bool AreAllArgsImmediates() const;
|
||||
|
||||
@@ -116,6 +123,7 @@ private:
|
||||
Inst* ge_inst;
|
||||
};
|
||||
Inst* overflow_inst = nullptr;
|
||||
Inst* nzcv_inst = nullptr;
|
||||
};
|
||||
|
||||
} // namespace IR
|
||||
|
||||
@@ -47,6 +47,7 @@ enum class Type {
|
||||
F64 = 1 << 11,
|
||||
F128 = 1 << 12,
|
||||
CoprocInfo = 1 << 13,
|
||||
NZCVFlags = 1 << 14,
|
||||
};
|
||||
|
||||
constexpr Type operator|(Type a, Type b) {
|
||||
|
||||
@@ -35,10 +35,14 @@ A32OPC(GetFpscrNZCV, T::U32,
|
||||
A32OPC(SetFpscrNZCV, T::Void, T::U32, )
|
||||
|
||||
// A64 Context getters/setters
|
||||
A64OPC(GetCFlag, T::U1, )
|
||||
A64OPC(SetNZCV, T::Void, T::NZCVFlags )
|
||||
A64OPC(GetW, T::U32, T::A64Reg )
|
||||
A64OPC(GetX, T::U64, T::A64Reg )
|
||||
A64OPC(GetSP, T::U64, )
|
||||
A64OPC(SetW, T::Void, T::A64Reg, T::U32 )
|
||||
A64OPC(SetX, T::Void, T::A64Reg, T::U64 )
|
||||
A64OPC(SetSP, T::Void, T::U64 )
|
||||
|
||||
// Hints
|
||||
OPCODE(PushRSB, T::Void, T::U64 )
|
||||
@@ -47,6 +51,7 @@ OPCODE(PushRSB, T::Void, T::U64
|
||||
OPCODE(GetCarryFromOp, T::U1, T::U32 )
|
||||
OPCODE(GetOverflowFromOp, T::U1, T::U32 )
|
||||
OPCODE(GetGEFromOp, T::U32, T::U32 )
|
||||
OPCODE(GetNZCVFromOp, T::NZCVFlags, T::Opaque )
|
||||
|
||||
// Calculations
|
||||
OPCODE(Pack2x32To1x64, T::U64, T::U32, T::U32 )
|
||||
@@ -66,22 +71,26 @@ OPCODE(ArithmeticShiftRight64, T::U64, T::U64, T::U8
|
||||
OPCODE(RotateRight32, T::U32, T::U32, T::U8, T::U1 )
|
||||
OPCODE(RotateRight64, T::U64, T::U64, T::U8 )
|
||||
OPCODE(RotateRightExtended, T::U32, T::U32, T::U1 )
|
||||
OPCODE(AddWithCarry, T::U32, T::U32, T::U32, T::U1 )
|
||||
OPCODE(SubWithCarry, T::U32, T::U32, T::U32, T::U1 )
|
||||
OPCODE(Add64, T::U64, T::U64, T::U64 )
|
||||
OPCODE(Sub64, T::U64, T::U64, T::U64 )
|
||||
OPCODE(Mul, T::U32, T::U32, T::U32 )
|
||||
OPCODE(Add32, T::U32, T::U32, T::U32, T::U1 )
|
||||
OPCODE(Add64, T::U64, T::U64, T::U64, T::U1 )
|
||||
OPCODE(Sub32, T::U32, T::U32, T::U32, T::U1 )
|
||||
OPCODE(Sub64, T::U64, T::U64, T::U64, T::U1 )
|
||||
OPCODE(Mul32, T::U32, T::U32, T::U32 )
|
||||
OPCODE(Mul64, T::U64, T::U64, T::U64 )
|
||||
OPCODE(And, T::U32, T::U32, T::U32 )
|
||||
OPCODE(Eor, T::U32, T::U32, T::U32 )
|
||||
OPCODE(Or, T::U32, T::U32, T::U32 )
|
||||
OPCODE(Not, T::U32, T::U32 )
|
||||
OPCODE(SignExtendWordToLong, T::U64, T::U32 )
|
||||
OPCODE(SignExtendHalfToWord, T::U32, T::U16 )
|
||||
OPCODE(SignExtendByteToWord, T::U32, T::U8 )
|
||||
OPCODE(ZeroExtendWordToLong, T::U64, T::U32 )
|
||||
OPCODE(ZeroExtendHalfToWord, T::U32, T::U16 )
|
||||
OPCODE(SignExtendHalfToWord, T::U32, T::U16 )
|
||||
OPCODE(SignExtendByteToLong, T::U64, T::U8 )
|
||||
OPCODE(SignExtendHalfToLong, T::U64, T::U16 )
|
||||
OPCODE(SignExtendWordToLong, T::U64, T::U32 )
|
||||
OPCODE(ZeroExtendByteToWord, T::U32, T::U8 )
|
||||
OPCODE(ZeroExtendHalfToWord, T::U32, T::U16 )
|
||||
OPCODE(ZeroExtendByteToLong, T::U64, T::U8 )
|
||||
OPCODE(ZeroExtendHalfToLong, T::U64, T::U16 )
|
||||
OPCODE(ZeroExtendWordToLong, T::U64, T::U32 )
|
||||
OPCODE(ByteReverseWord, T::U32, T::U32 )
|
||||
OPCODE(ByteReverseHalf, T::U16, T::U16 )
|
||||
OPCODE(ByteReverseDual, T::U64, T::U64 )
|
||||
|
||||
@@ -94,10 +94,12 @@ using U16 = TypedValue<Type::U16>;
|
||||
using U32 = TypedValue<Type::U32>;
|
||||
using U64 = TypedValue<Type::U64>;
|
||||
using U32U64 = TypedValue<Type::U32 | Type::U64>;
|
||||
using UAny = TypedValue<Type::U8 | Type::U16 | Type::U32 | Type::U64>;
|
||||
using F32 = TypedValue<Type::F32>;
|
||||
using F64 = TypedValue<Type::F64>;
|
||||
using F128 = TypedValue<Type::F128>;
|
||||
using F32F64 = TypedValue<Type::F32 | Type::F64>;
|
||||
using NZCV = TypedValue<Type::NZCVFlags>;
|
||||
|
||||
} // namespace IR
|
||||
} // namespace Dynarmic
|
||||
|
||||
Reference in New Issue
Block a user