/* This file is part of the dynarmic project. * Copyright (c) 2016 MerryMage * This software may be used and distributed according to the terms of the GNU * General Public License version 2 or any later version. */ #include "common/assert.h" #include "frontend/ir/ir_emitter.h" #include "frontend/ir/opcodes.h" namespace Dynarmic::IR { U1 IREmitter::Imm1(bool imm1) { return U1(Value(imm1)); } U8 IREmitter::Imm8(u8 imm8) { return U8(Value(imm8)); } U16 IREmitter::Imm16(u16 imm16) { return U16(Value(imm16)); } U32 IREmitter::Imm32(u32 imm32) { return U32(Value(imm32)); } U64 IREmitter::Imm64(u64 imm64) { return U64(Value(imm64)); } void IREmitter::PushRSB(const LocationDescriptor& return_location) { Inst(Opcode::PushRSB, IR::Value(return_location.Value())); } U64 IREmitter::Pack2x32To1x64(const U32& lo, const U32& hi) { return Inst(Opcode::Pack2x32To1x64, lo, hi); } U128 IREmitter::Pack2x64To1x128(const U64& lo, const U64& hi) { return Inst(Opcode::Pack2x64To1x128, lo, hi); } U32 IREmitter::LeastSignificantWord(const U64& value) { return Inst(Opcode::LeastSignificantWord, value); } ResultAndCarry IREmitter::MostSignificantWord(const U64& value) { auto result = Inst(Opcode::MostSignificantWord, value); auto carry_out = Inst(Opcode::GetCarryFromOp, result); return {result, carry_out}; } U16 IREmitter::LeastSignificantHalf(U32U64 value) { if (value.GetType() == Type::U64) { value = LeastSignificantWord(value); } return Inst(Opcode::LeastSignificantHalf, value); } U8 IREmitter::LeastSignificantByte(U32U64 value) { if (value.GetType() == Type::U64) { value = LeastSignificantWord(value); } return Inst(Opcode::LeastSignificantByte, value); } U1 IREmitter::MostSignificantBit(const U32& value) { return Inst(Opcode::MostSignificantBit, value); } U1 IREmitter::IsZero(const U32& value) { return Inst(Opcode::IsZero32, value); } U1 IREmitter::IsZero(const U64& value) { return Inst(Opcode::IsZero64, value); } U1 IREmitter::IsZero(const U32U64& value) { if (value.GetType() == Type::U32) { return Inst(Opcode::IsZero32, value); } else { return Inst(Opcode::IsZero64, value); } } U1 IREmitter::TestBit(const U32U64& value, const U8& bit) { if (value.GetType() == Type::U32) { return Inst(Opcode::TestBit, IndeterminateExtendToLong(value), bit); } else { return Inst(Opcode::TestBit, value, bit); } } U32 IREmitter::ConditionalSelect(Cond cond, const U32& a, const U32& b) { return Inst(Opcode::ConditionalSelect32, Value{cond}, a, b); } U64 IREmitter::ConditionalSelect(Cond cond, const U64& a, const U64& b) { return Inst(Opcode::ConditionalSelect64, Value{cond}, a, b); } NZCV IREmitter::ConditionalSelect(Cond cond, const NZCV& a, const NZCV& b) { return Inst(Opcode::ConditionalSelectNZCV, Value{cond}, a, b); } U32U64 IREmitter::ConditionalSelect(Cond cond, const U32U64& a, const U32U64& b) { ASSERT(a.GetType() == b.GetType()); if (a.GetType() == Type::U32) { return Inst(Opcode::ConditionalSelect32, Value{cond}, a, b); } else { return Inst(Opcode::ConditionalSelect64, Value{cond}, a, b); } } NZCV IREmitter::NZCVFromPackedFlags(const U32& a) { return Inst(Opcode::NZCVFromPackedFlags, a); } NZCV IREmitter::NZCVFrom(const Value& value) { return Inst(Opcode::GetNZCVFromOp, value); } ResultAndCarry IREmitter::LogicalShiftLeft(const U32& value_in, const U8& shift_amount, const U1& carry_in) { auto result = Inst(Opcode::LogicalShiftLeft32, value_in, shift_amount, carry_in); auto carry_out = Inst(Opcode::GetCarryFromOp, result); return {result, carry_out}; } ResultAndCarry IREmitter::LogicalShiftRight(const U32& value_in, const U8& shift_amount, const U1& carry_in) { auto result = Inst(Opcode::LogicalShiftRight32, value_in, shift_amount, carry_in); auto carry_out = Inst(Opcode::GetCarryFromOp, result); return {result, carry_out}; } ResultAndCarry IREmitter::ArithmeticShiftRight(const U32& value_in, const U8& shift_amount, const U1& carry_in) { auto result = Inst(Opcode::ArithmeticShiftRight32, value_in, shift_amount, carry_in); auto carry_out = Inst(Opcode::GetCarryFromOp, result); return {result, carry_out}; } ResultAndCarry IREmitter::RotateRight(const U32& value_in, const U8& shift_amount, const U1& carry_in) { auto result = Inst(Opcode::RotateRight32, value_in, shift_amount, carry_in); auto carry_out = Inst(Opcode::GetCarryFromOp, result); return {result, carry_out}; } ResultAndCarry IREmitter::RotateRightExtended(const U32& value_in, const U1& carry_in) { auto result = Inst(Opcode::RotateRightExtended, value_in, carry_in); auto carry_out = Inst(Opcode::GetCarryFromOp, result); return {result, carry_out}; } U32 IREmitter::LogicalShiftLeft(const U32& value_in, const U8& shift_amount) { return Inst(Opcode::LogicalShiftLeft32, value_in, shift_amount, Imm1(0)); } U64 IREmitter::LogicalShiftLeft(const U64& value_in, const U8& shift_amount) { return Inst(Opcode::LogicalShiftLeft64, value_in, shift_amount); } U32 IREmitter::LogicalShiftRight(const U32& value_in, const U8& shift_amount) { return Inst(Opcode::LogicalShiftRight32, value_in, shift_amount, Imm1(0)); } U64 IREmitter::LogicalShiftRight(const U64& value_in, const U8& shift_amount) { return Inst(Opcode::LogicalShiftRight64, value_in, shift_amount); } U32U64 IREmitter::LogicalShiftLeft(const U32U64& value_in, const U8& shift_amount) { if (value_in.GetType() == Type::U32) { return Inst(Opcode::LogicalShiftLeft32, value_in, shift_amount, Imm1(0)); } else { return Inst(Opcode::LogicalShiftLeft64, value_in, shift_amount); } } U32U64 IREmitter::LogicalShiftRight(const U32U64& value_in, const U8& shift_amount) { if (value_in.GetType() == Type::U32) { return Inst(Opcode::LogicalShiftRight32, value_in, shift_amount, Imm1(0)); } else { return Inst(Opcode::LogicalShiftRight64, value_in, shift_amount); } } U32U64 IREmitter::ArithmeticShiftRight(const U32U64& value_in, const U8& shift_amount) { if (value_in.GetType() == Type::U32) { return Inst(Opcode::ArithmeticShiftRight32, value_in, shift_amount, Imm1(0)); } else { return Inst(Opcode::ArithmeticShiftRight64, value_in, shift_amount); } } U32U64 IREmitter::RotateRight(const U32U64& value_in, const U8& shift_amount) { if (value_in.GetType() == Type::U32) { return Inst(Opcode::RotateRight32, value_in, shift_amount, Imm1(0)); } else { return Inst(Opcode::RotateRight64, value_in, shift_amount); } } ResultAndCarryAndOverflow IREmitter::AddWithCarry(const U32& a, const U32& b, const U1& carry_in) { auto result = Inst(Opcode::Add32, a, b, carry_in); auto carry_out = Inst(Opcode::GetCarryFromOp, result); auto overflow = Inst(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(Opcode::Add32, a, b, carry_in); } else { return Inst(Opcode::Add64, a, b, carry_in); } } U32 IREmitter::Add(const U32& a, const U32& b) { return Inst(Opcode::Add32, a, b, Imm1(0)); } U64 IREmitter::Add(const U64& a, const U64& b) { return Inst(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(Opcode::Add32, a, b, Imm1(0)); } else { return Inst(Opcode::Add64, a, b, Imm1(0)); } } ResultAndCarryAndOverflow 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(Opcode::Sub32, a, b, carry_in); auto carry_out = Inst(Opcode::GetCarryFromOp, result); auto overflow = Inst(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(Opcode::Sub32, a, b, carry_in); } else { return Inst(Opcode::Sub64, a, b, carry_in); } } U32 IREmitter::Sub(const U32& a, const U32& b) { return Inst(Opcode::Sub32, a, b, Imm1(1)); } U64 IREmitter::Sub(const U64& a, const U64& b) { return Inst(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(Opcode::Sub32, a, b, Imm1(1)); } else { return Inst(Opcode::Sub64, a, b, Imm1(1)); } } U32 IREmitter::Mul(const U32& a, const U32& b) { return Inst(Opcode::Mul32, a, b); } U64 IREmitter::Mul(const U64& a, const U64& b) { return Inst(Opcode::Mul64, a, b); } U32U64 IREmitter::Mul(const U32U64& a, const U32U64& b) { if (a.GetType() == Type::U32) { return Inst(Opcode::Mul32, a, b); } return Inst(Opcode::Mul64, a, b); } U64 IREmitter::UnsignedMultiplyHigh(const U64& a, const U64& b) { return Inst(Opcode::UnsignedMultiplyHigh64, a, b); } U64 IREmitter::SignedMultiplyHigh(const U64& a, const U64& b) { return Inst(Opcode::SignedMultiplyHigh64, a, b); } U32 IREmitter::UnsignedDiv(const U32& a, const U32& b) { return Inst(Opcode::UnsignedDiv32, a, b); } U64 IREmitter::UnsignedDiv(const U64& a, const U64& b) { return Inst(Opcode::UnsignedDiv64, a, b); } U32U64 IREmitter::UnsignedDiv(const U32U64& a, const U32U64& b) { if (a.GetType() == Type::U32) { return Inst(Opcode::UnsignedDiv32, a, b); } return Inst(Opcode::UnsignedDiv64, a, b); } U32 IREmitter::SignedDiv(const U32& a, const U32& b) { return Inst(Opcode::SignedDiv32, a, b); } U64 IREmitter::SignedDiv(const U64& a, const U64& b) { return Inst(Opcode::SignedDiv64, a, b); } U32U64 IREmitter::SignedDiv(const U32U64& a, const U32U64& b) { if (a.GetType() == Type::U32) { return Inst(Opcode::SignedDiv32, a, b); } return Inst(Opcode::SignedDiv64, a, b); } U32 IREmitter::And(const U32& a, const U32& b) { return Inst(Opcode::And32, a, b); } U32U64 IREmitter::And(const U32U64& a, const U32U64& b) { ASSERT(a.GetType() == b.GetType()); if (a.GetType() == Type::U32) { return Inst(Opcode::And32, a, b); } else { return Inst(Opcode::And64, a, b); } } U32 IREmitter::Eor(const U32& a, const U32& b) { return Inst(Opcode::Eor32, a, b); } U32U64 IREmitter::Eor(const U32U64& a, const U32U64& b) { ASSERT(a.GetType() == b.GetType()); if (a.GetType() == Type::U32) { return Inst(Opcode::Eor32, a, b); } else { return Inst(Opcode::Eor64, a, b); } } U32 IREmitter::Or(const U32& a, const U32& b) { return Inst(Opcode::Or32, a, b); } U32U64 IREmitter::Or(const U32U64& a, const U32U64& b) { ASSERT(a.GetType() == b.GetType()); if (a.GetType() == Type::U32) { return Inst(Opcode::Or32, a, b); } else { return Inst(Opcode::Or64, a, b); } } U32 IREmitter::Not(const U32& a) { return Inst(Opcode::Not32, a); } U32U64 IREmitter::Not(const U32U64& a) { if (a.GetType() == Type::U32) { return Inst(Opcode::Not32, a); } else { return Inst(Opcode::Not64, a); } } U64 IREmitter::SignExtendToLong(const UAny& a) { switch (a.GetType()) { case Type::U8: return Inst(Opcode::SignExtendByteToLong, a); case Type::U16: return Inst(Opcode::SignExtendHalfToLong, a); case Type::U32: return Inst(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(Opcode::SignExtendByteToWord, a); case Type::U16: return Inst(Opcode::SignExtendHalfToWord, a); case Type::U32: return U32(a); case Type::U64: return Inst(Opcode::LeastSignificantWord, a); default: ASSERT_MSG(false, "Unreachable"); return {}; } } U64 IREmitter::SignExtendWordToLong(const U32& a) { return Inst(Opcode::SignExtendWordToLong, a); } U32 IREmitter::SignExtendHalfToWord(const U16& a) { return Inst(Opcode::SignExtendHalfToWord, a); } U32 IREmitter::SignExtendByteToWord(const U8& a) { return Inst(Opcode::SignExtendByteToWord, a); } U64 IREmitter::ZeroExtendToLong(const UAny& a) { switch (a.GetType()) { case Type::U8: return Inst(Opcode::ZeroExtendByteToLong, a); case Type::U16: return Inst(Opcode::ZeroExtendHalfToLong, a); case Type::U32: return Inst(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(Opcode::ZeroExtendByteToWord, a); case Type::U16: return Inst(Opcode::ZeroExtendHalfToWord, a); case Type::U32: return U32(a); case Type::U64: return Inst(Opcode::LeastSignificantWord, a); default: ASSERT_MSG(false, "Unreachable"); return {}; } } U128 IREmitter::ZeroExtendToQuad(const UAny& a) { return Inst(Opcode::ZeroExtendLongToQuad, ZeroExtendToLong(a)); } U64 IREmitter::ZeroExtendWordToLong(const U32& a) { return Inst(Opcode::ZeroExtendWordToLong, a); } U32 IREmitter::ZeroExtendHalfToWord(const U16& a) { return Inst(Opcode::ZeroExtendHalfToWord, a); } U32 IREmitter::ZeroExtendByteToWord(const U8& a) { return Inst(Opcode::ZeroExtendByteToWord, a); } U32 IREmitter::IndeterminateExtendToWord(const UAny& a) { // TODO: Implement properly return ZeroExtendToWord(a); } U64 IREmitter::IndeterminateExtendToLong(const UAny& a) { // TODO: Implement properly return ZeroExtendToLong(a); } U32 IREmitter::ByteReverseWord(const U32& a) { return Inst(Opcode::ByteReverseWord, a); } U16 IREmitter::ByteReverseHalf(const U16& a) { return Inst(Opcode::ByteReverseHalf, a); } U64 IREmitter::ByteReverseDual(const U64& a) { return Inst(Opcode::ByteReverseDual, a); } U32 IREmitter::CountLeadingZeros(const U32& a) { return Inst(Opcode::CountLeadingZeros32, a); } U64 IREmitter::CountLeadingZeros(const U64& a) { return Inst(Opcode::CountLeadingZeros64, a); } U32U64 IREmitter::CountLeadingZeros(const U32U64& a) { if (a.GetType() == IR::Type::U32) { return Inst(Opcode::CountLeadingZeros32, a); } return Inst(Opcode::CountLeadingZeros64, a); } U32 IREmitter::ExtractRegister(const U32& a, const U32& b, const U8& lsb) { return Inst(Opcode::ExtractRegister32, a, b, lsb); } U64 IREmitter::ExtractRegister(const U64& a, const U64& b, const U8& lsb) { return Inst(Opcode::ExtractRegister64, a, b, lsb); } U32U64 IREmitter::ExtractRegister(const U32U64& a, const U32U64& b, const U8& lsb) { if (a.GetType() == IR::Type::U32) { return Inst(Opcode::ExtractRegister32, a, b, lsb); } return Inst(Opcode::ExtractRegister64, a, b, lsb); } ResultAndOverflow IREmitter::SignedSaturatedAdd(const U32& a, const U32& b) { auto result = Inst(Opcode::SignedSaturatedAdd, a, b); auto overflow = Inst(Opcode::GetOverflowFromOp, result); return {result, overflow}; } ResultAndOverflow IREmitter::SignedSaturatedSub(const U32& a, const U32& b) { auto result = Inst(Opcode::SignedSaturatedSub, a, b); auto overflow = Inst(Opcode::GetOverflowFromOp, result); return {result, overflow}; } ResultAndOverflow IREmitter::UnsignedSaturation(const U32& a, size_t bit_size_to_saturate_to) { ASSERT(bit_size_to_saturate_to <= 31); auto result = Inst(Opcode::UnsignedSaturation, a, Imm8(static_cast(bit_size_to_saturate_to))); auto overflow = Inst(Opcode::GetOverflowFromOp, result); return {result, overflow}; } ResultAndOverflow IREmitter::SignedSaturation(const U32& a, size_t bit_size_to_saturate_to) { ASSERT(bit_size_to_saturate_to >= 1 && bit_size_to_saturate_to <= 32); auto result = Inst(Opcode::SignedSaturation, a, Imm8(static_cast(bit_size_to_saturate_to))); auto overflow = Inst(Opcode::GetOverflowFromOp, result); return {result, overflow}; } ResultAndGE IREmitter::PackedAddU8(const U32& a, const U32& b) { auto result = Inst(Opcode::PackedAddU8, a, b); auto ge = Inst(Opcode::GetGEFromOp, result); return {result, ge}; } ResultAndGE IREmitter::PackedAddS8(const U32& a, const U32& b) { auto result = Inst(Opcode::PackedAddS8, a, b); auto ge = Inst(Opcode::GetGEFromOp, result); return {result, ge}; } ResultAndGE IREmitter::PackedAddU16(const U32& a, const U32& b) { auto result = Inst(Opcode::PackedAddU16, a, b); auto ge = Inst(Opcode::GetGEFromOp, result); return {result, ge}; } ResultAndGE IREmitter::PackedAddS16(const U32& a, const U32& b) { auto result = Inst(Opcode::PackedAddS16, a, b); auto ge = Inst(Opcode::GetGEFromOp, result); return {result, ge}; } ResultAndGE IREmitter::PackedSubU8(const U32& a, const U32& b) { auto result = Inst(Opcode::PackedSubU8, a, b); auto ge = Inst(Opcode::GetGEFromOp, result); return {result, ge}; } ResultAndGE IREmitter::PackedSubS8(const U32& a, const U32& b) { auto result = Inst(Opcode::PackedSubS8, a, b); auto ge = Inst(Opcode::GetGEFromOp, result); return {result, ge}; } ResultAndGE IREmitter::PackedSubU16(const U32& a, const U32& b) { auto result = Inst(Opcode::PackedSubU16, a, b); auto ge = Inst(Opcode::GetGEFromOp, result); return {result, ge}; } ResultAndGE IREmitter::PackedSubS16(const U32& a, const U32& b) { auto result = Inst(Opcode::PackedSubS16, a, b); auto ge = Inst(Opcode::GetGEFromOp, result); return {result, ge}; } ResultAndGE IREmitter::PackedAddSubU16(const U32& a, const U32& b) { auto result = Inst(Opcode::PackedAddSubU16, a, b); auto ge = Inst(Opcode::GetGEFromOp, result); return {result, ge}; } ResultAndGE IREmitter::PackedAddSubS16(const U32& a, const U32& b) { auto result = Inst(Opcode::PackedAddSubS16, a, b); auto ge = Inst(Opcode::GetGEFromOp, result); return {result, ge}; } ResultAndGE IREmitter::PackedSubAddU16(const U32& a, const U32& b) { auto result = Inst(Opcode::PackedSubAddU16, a, b); auto ge = Inst(Opcode::GetGEFromOp, result); return {result, ge}; } ResultAndGE IREmitter::PackedSubAddS16(const U32& a, const U32& b) { auto result = Inst(Opcode::PackedSubAddS16, a, b); auto ge = Inst(Opcode::GetGEFromOp, result); return {result, ge}; } U32 IREmitter::PackedHalvingAddU8(const U32& a, const U32& b) { return Inst(Opcode::PackedHalvingAddU8, a, b); } U32 IREmitter::PackedHalvingAddS8(const U32& a, const U32& b) { return Inst(Opcode::PackedHalvingAddS8, a, b); } U32 IREmitter::PackedHalvingSubU8(const U32& a, const U32& b) { return Inst(Opcode::PackedHalvingSubU8, a, b); } U32 IREmitter::PackedHalvingSubS8(const U32& a, const U32& b) { return Inst(Opcode::PackedHalvingSubS8, a, b); } U32 IREmitter::PackedHalvingAddU16(const U32& a, const U32& b) { return Inst(Opcode::PackedHalvingAddU16, a, b); } U32 IREmitter::PackedHalvingAddS16(const U32& a, const U32& b) { return Inst(Opcode::PackedHalvingAddS16, a, b); } U32 IREmitter::PackedHalvingSubU16(const U32& a, const U32& b) { return Inst(Opcode::PackedHalvingSubU16, a, b); } U32 IREmitter::PackedHalvingSubS16(const U32& a, const U32& b) { return Inst(Opcode::PackedHalvingSubS16, a, b); } U32 IREmitter::PackedHalvingAddSubU16(const U32& a, const U32& b) { return Inst(Opcode::PackedHalvingAddSubU16, a, b); } U32 IREmitter::PackedHalvingAddSubS16(const U32& a, const U32& b) { return Inst(Opcode::PackedHalvingAddSubS16, a, b); } U32 IREmitter::PackedHalvingSubAddU16(const U32& a, const U32& b) { return Inst(Opcode::PackedHalvingSubAddU16, a, b); } U32 IREmitter::PackedHalvingSubAddS16(const U32& a, const U32& b) { return Inst(Opcode::PackedHalvingSubAddS16, a, b); } U32 IREmitter::PackedSaturatedAddU8(const U32& a, const U32& b) { return Inst(Opcode::PackedSaturatedAddU8, a, b); } U32 IREmitter::PackedSaturatedAddS8(const U32& a, const U32& b) { return Inst(Opcode::PackedSaturatedAddS8, a, b); } U32 IREmitter::PackedSaturatedSubU8(const U32& a, const U32& b) { return Inst(Opcode::PackedSaturatedSubU8, a, b); } U32 IREmitter::PackedSaturatedSubS8(const U32& a, const U32& b) { return Inst(Opcode::PackedSaturatedSubS8, a, b); } U32 IREmitter::PackedSaturatedAddU16(const U32& a, const U32& b) { return Inst(Opcode::PackedSaturatedAddU16, a, b); } U32 IREmitter::PackedSaturatedAddS16(const U32& a, const U32& b) { return Inst(Opcode::PackedSaturatedAddS16, a, b); } U32 IREmitter::PackedSaturatedSubU16(const U32& a, const U32& b) { return Inst(Opcode::PackedSaturatedSubU16, a, b); } U32 IREmitter::PackedSaturatedSubS16(const U32& a, const U32& b) { return Inst(Opcode::PackedSaturatedSubS16, a, b); } U32 IREmitter::PackedAbsDiffSumS8(const U32& a, const U32& b) { return Inst(Opcode::PackedAbsDiffSumS8, a, b); } U32 IREmitter::PackedSelect(const U32& ge, const U32& a, const U32& b) { return Inst(Opcode::PackedSelect, ge, a, b); } U32 IREmitter::CRC32Castagnoli8(const U32& a, const U32& b) { return Inst(Opcode::CRC32Castagnoli8, a, b); } U32 IREmitter::CRC32Castagnoli16(const U32& a, const U32& b) { return Inst(Opcode::CRC32Castagnoli16, a, b); } U32 IREmitter::CRC32Castagnoli32(const U32& a, const U32& b) { return Inst(Opcode::CRC32Castagnoli32, a, b); } U32 IREmitter::CRC32Castagnoli64(const U32& a, const U64& b) { return Inst(Opcode::CRC32Castagnoli64, a, b); } U32 IREmitter::CRC32ISO8(const U32& a, const U32& b) { return Inst(Opcode::CRC32ISO8, a, b); } U32 IREmitter::CRC32ISO16(const U32& a, const U32& b) { return Inst(Opcode::CRC32ISO16, a, b); } U32 IREmitter::CRC32ISO32(const U32& a, const U32& b) { return Inst(Opcode::CRC32ISO32, a, b); } U32 IREmitter::CRC32ISO64(const U32& a, const U64& b) { return Inst(Opcode::CRC32ISO64, a, b); } U128 IREmitter::AESDecryptSingleRound(const U128& a) { return Inst(Opcode::AESDecryptSingleRound, a); } U128 IREmitter::AESEncryptSingleRound(const U128& a) { return Inst(Opcode::AESEncryptSingleRound, a); } U128 IREmitter::AESInverseMixColumns(const U128& a) { return Inst(Opcode::AESInverseMixColumns, a); } U128 IREmitter::AESMixColumns(const U128& a) { return Inst(Opcode::AESMixColumns, a); } UAny IREmitter::VectorGetElement(size_t esize, const U128& a, size_t index) { ASSERT_MSG(esize * index < 128, "Invalid index"); switch (esize) { case 8: return Inst(Opcode::VectorGetElement8, a, Imm8(static_cast(index))); case 16: return Inst(Opcode::VectorGetElement16, a, Imm8(static_cast(index))); case 32: return Inst(Opcode::VectorGetElement32, a, Imm8(static_cast(index))); case 64: return Inst(Opcode::VectorGetElement64, a, Imm8(static_cast(index))); default: ASSERT_MSG(false, "Unreachable"); return {}; } } U128 IREmitter::VectorSetElement(size_t esize, const U128& a, size_t index, const IR::UAny& elem) { ASSERT_MSG(esize * index < 128, "Invalid index"); switch (esize) { case 8: return Inst(Opcode::VectorSetElement8, a, Imm8(static_cast(index)), elem); case 16: return Inst(Opcode::VectorSetElement16, a, Imm8(static_cast(index)), elem); case 32: return Inst(Opcode::VectorSetElement32, a, Imm8(static_cast(index)), elem); case 64: return Inst(Opcode::VectorSetElement64, a, Imm8(static_cast(index)), elem); default: ASSERT_MSG(false, "Unreachable"); return {}; } } U128 IREmitter::VectorAdd(size_t esize, const U128& a, const U128& b) { switch (esize) { case 8: return Inst(Opcode::VectorAdd8, a, b); case 16: return Inst(Opcode::VectorAdd16, a, b); case 32: return Inst(Opcode::VectorAdd32, a, b); case 64: return Inst(Opcode::VectorAdd64, a, b); } UNREACHABLE(); return {}; } U128 IREmitter::VectorAnd(const U128& a, const U128& b) { return Inst(Opcode::VectorAnd, a, b); } U128 IREmitter::VectorArithmeticShiftRight(size_t esize, const U128& a, u8 shift_amount) { switch (esize) { case 8: return Inst(Opcode::VectorArithmeticShiftRight8, a, Imm8(shift_amount)); case 16: return Inst(Opcode::VectorArithmeticShiftRight16, a, Imm8(shift_amount)); case 32: return Inst(Opcode::VectorArithmeticShiftRight32, a, Imm8(shift_amount)); case 64: return Inst(Opcode::VectorArithmeticShiftRight64, a, Imm8(shift_amount)); } UNREACHABLE(); return {}; } U128 IREmitter::VectorBroadcastLower(size_t esize, const UAny& a) { switch (esize) { case 8: return Inst(Opcode::VectorBroadcastLower8, U8(a)); case 16: return Inst(Opcode::VectorBroadcastLower16, U16(a)); case 32: return Inst(Opcode::VectorBroadcastLower32, U32(a)); } UNREACHABLE(); return {}; } U128 IREmitter::VectorBroadcast(size_t esize, const UAny& a) { switch (esize) { case 8: return Inst(Opcode::VectorBroadcast8, U8(a)); case 16: return Inst(Opcode::VectorBroadcast16, U16(a)); case 32: return Inst(Opcode::VectorBroadcast32, U32(a)); case 64: return Inst(Opcode::VectorBroadcast64, U64(a)); } UNREACHABLE(); return {}; } U128 IREmitter::VectorEor(const U128& a, const U128& b) { return Inst(Opcode::VectorEor, a, b); } U128 IREmitter::VectorEqual(size_t esize, const U128& a, const U128& b) { switch (esize) { case 8: return Inst(Opcode::VectorEqual8, a, b); case 16: return Inst(Opcode::VectorEqual16, a, b); case 32: return Inst(Opcode::VectorEqual32, a, b); case 64: return Inst(Opcode::VectorEqual64, a, b); case 128: return Inst(Opcode::VectorEqual128, a, b); } UNREACHABLE(); return {}; } U128 IREmitter::VectorGreaterSigned(size_t esize, const U128& a, const U128& b) { switch (esize) { case 8: return Inst(Opcode::VectorGreaterS8, a, b); case 16: return Inst(Opcode::VectorGreaterS16, a, b); case 32: return Inst(Opcode::VectorGreaterS32, a, b); case 64: return Inst(Opcode::VectorGreaterS64, a, b); } UNREACHABLE(); return {}; } U128 IREmitter::VectorGreaterEqualSigned(size_t esize, const U128& a, const U128& b) { return VectorOr(VectorGreaterSigned(esize, a, b), VectorEqual(esize, a, b)); } U128 IREmitter::VectorGreaterEqualUnsigned(size_t esize, const U128& a, const U128& b) { return VectorEqual(esize, VectorMaxUnsigned(esize, a, b), a); } U128 IREmitter::VectorGreaterUnsigned(size_t esize, const U128& a, const U128& b) { return VectorNot(VectorEqual(esize, VectorMinUnsigned(esize, a, b), a)); } U128 IREmitter::VectorInterleaveLower(size_t esize, const U128& a, const U128& b) { switch (esize) { case 8: return Inst(Opcode::VectorInterleaveLower8, a, b); case 16: return Inst(Opcode::VectorInterleaveLower16, a, b); case 32: return Inst(Opcode::VectorInterleaveLower32, a, b); case 64: return Inst(Opcode::VectorInterleaveLower64, a, b); } UNREACHABLE(); return {}; } U128 IREmitter::VectorLessEqualSigned(size_t esize, const U128& a, const U128& b) { return VectorNot(VectorGreaterSigned(esize, a, b)); } U128 IREmitter::VectorLessEqualUnsigned(size_t esize, const U128& a, const U128& b) { return VectorEqual(esize, VectorMinUnsigned(esize, a, b), a); } U128 IREmitter::VectorLessSigned(size_t esize, const U128& a, const U128& b) { return VectorNot(VectorOr(VectorGreaterSigned(esize, a, b), VectorEqual(esize, a, b))); } U128 IREmitter::VectorLessUnsigned(size_t esize, const U128& a, const U128& b) { return VectorNot(VectorEqual(esize, VectorMaxUnsigned(esize, a, b), a)); } U128 IREmitter::VectorLogicalShiftLeft(size_t esize, const U128& a, u8 shift_amount) { switch (esize) { case 8: return Inst(Opcode::VectorLogicalShiftLeft8, a, Imm8(shift_amount)); case 16: return Inst(Opcode::VectorLogicalShiftLeft16, a, Imm8(shift_amount)); case 32: return Inst(Opcode::VectorLogicalShiftLeft32, a, Imm8(shift_amount)); case 64: return Inst(Opcode::VectorLogicalShiftLeft64, a, Imm8(shift_amount)); } UNREACHABLE(); return {}; } U128 IREmitter::VectorLogicalShiftRight(size_t esize, const U128& a, u8 shift_amount) { switch (esize) { case 8: return Inst(Opcode::VectorLogicalShiftRight8, a, Imm8(shift_amount)); case 16: return Inst(Opcode::VectorLogicalShiftRight16, a, Imm8(shift_amount)); case 32: return Inst(Opcode::VectorLogicalShiftRight32, a, Imm8(shift_amount)); case 64: return Inst(Opcode::VectorLogicalShiftRight64, a, Imm8(shift_amount)); } UNREACHABLE(); return {}; } U128 IREmitter::VectorMaxSigned(size_t esize, const U128& a, const U128& b) { switch (esize) { case 8: return Inst(Opcode::VectorMaxS8, a, b); case 16: return Inst(Opcode::VectorMaxS16, a, b); case 32: return Inst(Opcode::VectorMaxS32, a, b); case 64: return Inst(Opcode::VectorMaxS64, a, b); } UNREACHABLE(); return {}; } U128 IREmitter::VectorMaxUnsigned(size_t esize, const U128& a, const U128& b) { switch (esize) { case 8: return Inst(Opcode::VectorMaxU8, a, b); case 16: return Inst(Opcode::VectorMaxU16, a, b); case 32: return Inst(Opcode::VectorMaxU32, a, b); case 64: return Inst(Opcode::VectorMaxU64, a, b); } UNREACHABLE(); return {}; } U128 IREmitter::VectorMinSigned(size_t esize, const U128& a, const U128& b) { switch (esize) { case 8: return Inst(Opcode::VectorMinS8, a, b); case 16: return Inst(Opcode::VectorMinS16, a, b); case 32: return Inst(Opcode::VectorMinS32, a, b); case 64: return Inst(Opcode::VectorMinS64, a, b); } UNREACHABLE(); return {}; } U128 IREmitter::VectorMinUnsigned(size_t esize, const U128& a, const U128& b) { switch (esize) { case 8: return Inst(Opcode::VectorMinU8, a, b); case 16: return Inst(Opcode::VectorMinU16, a, b); case 32: return Inst(Opcode::VectorMinU32, a, b); case 64: return Inst(Opcode::VectorMinU64, a, b); } UNREACHABLE(); return {}; } U128 IREmitter::VectorMultiply(size_t esize, const U128& a, const U128& b) { switch (esize) { case 8: return Inst(Opcode::VectorMultiply8, a, b); case 16: return Inst(Opcode::VectorMultiply16, a, b); case 32: return Inst(Opcode::VectorMultiply32, a, b); case 64: return Inst(Opcode::VectorMultiply64, a, b); } UNREACHABLE(); return {}; } U128 IREmitter::VectorNarrow(size_t original_esize, const U128& a) { switch (original_esize) { case 16: return Inst(Opcode::VectorNarrow16, a); case 32: return Inst(Opcode::VectorNarrow32, a); case 64: return Inst(Opcode::VectorNarrow64, a); } UNREACHABLE(); return {}; } U128 IREmitter::VectorNot(const U128& a) { return Inst(Opcode::VectorNot, a); } U128 IREmitter::VectorOr(const U128& a, const U128& b) { return Inst(Opcode::VectorOr, a, b); } U128 IREmitter::VectorPairedAddLower(size_t esize, const U128& a, const U128& b) { switch (esize) { case 8: return Inst(Opcode::VectorPairedAddLower8, a, b); case 16: return Inst(Opcode::VectorPairedAddLower16, a, b); case 32: return Inst(Opcode::VectorPairedAddLower32, a, b); } UNREACHABLE(); return {}; } U128 IREmitter::VectorPairedAdd(size_t esize, const U128& a, const U128& b) { switch (esize) { case 8: return Inst(Opcode::VectorPairedAdd8, a, b); case 16: return Inst(Opcode::VectorPairedAdd16, a, b); case 32: return Inst(Opcode::VectorPairedAdd32, a, b); case 64: return Inst(Opcode::VectorPairedAdd64, a, b); } UNREACHABLE(); return {}; } U128 IREmitter::VectorPopulationCount(const U128& a) { return Inst(Opcode::VectorPopulationCount, a); } U128 IREmitter::VectorSignExtend(size_t original_esize, const U128& a) { switch (original_esize) { case 8: return Inst(Opcode::VectorSignExtend8, a); case 16: return Inst(Opcode::VectorSignExtend16, a); case 32: return Inst(Opcode::VectorSignExtend32, a); case 64: return Inst(Opcode::VectorSignExtend64, a); } UNREACHABLE(); return {}; } U128 IREmitter::VectorSub(size_t esize, const U128& a, const U128& b) { switch (esize) { case 8: return Inst(Opcode::VectorSub8, a, b); case 16: return Inst(Opcode::VectorSub16, a, b); case 32: return Inst(Opcode::VectorSub32, a, b); case 64: return Inst(Opcode::VectorSub64, a, b); } UNREACHABLE(); return {}; } U128 IREmitter::VectorZeroExtend(size_t original_esize, const U128& a) { switch (original_esize) { case 8: return Inst(Opcode::VectorZeroExtend8, a); case 16: return Inst(Opcode::VectorZeroExtend16, a); case 32: return Inst(Opcode::VectorZeroExtend32, a); case 64: return Inst(Opcode::VectorZeroExtend64, a); } UNREACHABLE(); return {}; } U128 IREmitter::VectorZeroUpper(const U128& a) { return Inst(Opcode::VectorZeroUpper, a); } U128 IREmitter::ZeroVector() { return Inst(Opcode::ZeroVector); } U32U64 IREmitter::FPAbs(const U32U64& a) { if (a.GetType() == Type::U32) { return Inst(Opcode::FPAbs32, a); } else { return Inst(Opcode::FPAbs64, a); } } U32U64 IREmitter::FPAdd(const U32U64& a, const U32U64& b, bool fpscr_controlled) { ASSERT(fpscr_controlled); ASSERT(a.GetType() == b.GetType()); if (a.GetType() == Type::U32) { return Inst(Opcode::FPAdd32, a, b); } else { return Inst(Opcode::FPAdd64, a, b); } } NZCV IREmitter::FPCompare(const U32U64& a, const U32U64& b, bool exc_on_qnan, bool fpscr_controlled) { ASSERT(fpscr_controlled); ASSERT(a.GetType() == b.GetType()); if (a.GetType() == Type::U32) { return Inst(Opcode::FPCompare32, a, b, Imm1(exc_on_qnan)); } else { return Inst(Opcode::FPCompare64, a, b, Imm1(exc_on_qnan)); } } U32U64 IREmitter::FPDiv(const U32U64& a, const U32U64& b, bool fpscr_controlled) { ASSERT(fpscr_controlled); ASSERT(a.GetType() == b.GetType()); if (a.GetType() == Type::U32) { return Inst(Opcode::FPDiv32, a, b); } else { return Inst(Opcode::FPDiv64, a, b); } } U32U64 IREmitter::FPMax(const U32U64& a, const U32U64& b, bool fpscr_controlled) { ASSERT(fpscr_controlled); ASSERT(a.GetType() == b.GetType()); if (a.GetType() == Type::U32) { return Inst(Opcode::FPMax32, a, b); } else { return Inst(Opcode::FPMax64, a, b); } } U32U64 IREmitter::FPMaxNumeric(const U32U64& a, const U32U64& b, bool fpscr_controlled) { ASSERT(fpscr_controlled); ASSERT(a.GetType() == b.GetType()); if (a.GetType() == Type::U32) { return Inst(Opcode::FPMaxNumeric32, a, b); } else { return Inst(Opcode::FPMaxNumeric64, a, b); } } U32U64 IREmitter::FPMin(const U32U64& a, const U32U64& b, bool fpscr_controlled) { ASSERT(fpscr_controlled); ASSERT(a.GetType() == b.GetType()); if (a.GetType() == Type::U32) { return Inst(Opcode::FPMin32, a, b); } else { return Inst(Opcode::FPMin64, a, b); } } U32U64 IREmitter::FPMinNumeric(const U32U64& a, const U32U64& b, bool fpscr_controlled) { ASSERT(fpscr_controlled); ASSERT(a.GetType() == b.GetType()); if (a.GetType() == Type::U32) { return Inst(Opcode::FPMinNumeric32, a, b); } else { return Inst(Opcode::FPMinNumeric64, a, b); } } U32U64 IREmitter::FPMul(const U32U64& a, const U32U64& b, bool fpscr_controlled) { ASSERT(fpscr_controlled); ASSERT(a.GetType() == b.GetType()); if (a.GetType() == Type::U32) { return Inst(Opcode::FPMul32, a, b); } else { return Inst(Opcode::FPMul64, a, b); } } U32U64 IREmitter::FPNeg(const U32U64& a) { if (a.GetType() == Type::U32) { return Inst(Opcode::FPNeg32, a); } else { return Inst(Opcode::FPNeg64, a); } } U32U64 IREmitter::FPSqrt(const U32U64& a) { if (a.GetType() == Type::U32) { return Inst(Opcode::FPSqrt32, a); } else { return Inst(Opcode::FPSqrt64, a); } } U32U64 IREmitter::FPSub(const U32U64& a, const U32U64& b, bool fpscr_controlled) { ASSERT(fpscr_controlled); ASSERT(a.GetType() == b.GetType()); if (a.GetType() == Type::U32) { return Inst(Opcode::FPSub32, a, b); } else { return Inst(Opcode::FPSub64, a, b); } } U32 IREmitter::FPDoubleToSingle(const U64& a, bool fpscr_controlled) { ASSERT(fpscr_controlled); return Inst(Opcode::FPDoubleToSingle, a); } U64 IREmitter::FPSingleToDouble(const U32& a, bool fpscr_controlled) { ASSERT(fpscr_controlled); return Inst(Opcode::FPSingleToDouble, a); } U32 IREmitter::FPSingleToS32(const U32& a, bool round_towards_zero, bool fpscr_controlled) { ASSERT(fpscr_controlled); return Inst(Opcode::FPSingleToS32, a, Imm1(round_towards_zero)); } U32 IREmitter::FPSingleToU32(const U32& a, bool round_towards_zero, bool fpscr_controlled) { ASSERT(fpscr_controlled); return Inst(Opcode::FPSingleToU32, a, Imm1(round_towards_zero)); } U32 IREmitter::FPDoubleToS32(const U64& a, bool round_towards_zero, bool fpscr_controlled) { ASSERT(fpscr_controlled); return Inst(Opcode::FPDoubleToS32, a, Imm1(round_towards_zero)); } U32 IREmitter::FPDoubleToU32(const U64& a, bool round_towards_zero, bool fpscr_controlled) { ASSERT(fpscr_controlled); return Inst(Opcode::FPDoubleToU32, a, Imm1(round_towards_zero)); } U32 IREmitter::FPS32ToSingle(const U32& a, bool round_to_nearest, bool fpscr_controlled) { ASSERT(fpscr_controlled); return Inst(Opcode::FPS32ToSingle, a, Imm1(round_to_nearest)); } U32 IREmitter::FPU32ToSingle(const U32& a, bool round_to_nearest, bool fpscr_controlled) { ASSERT(fpscr_controlled); return Inst(Opcode::FPU32ToSingle, a, Imm1(round_to_nearest)); } U64 IREmitter::FPS32ToDouble(const U32& a, bool round_to_nearest, bool fpscr_controlled) { ASSERT(fpscr_controlled); return Inst(Opcode::FPS32ToDouble, a, Imm1(round_to_nearest)); } U64 IREmitter::FPU32ToDouble(const U32& a, bool round_to_nearest, bool fpscr_controlled) { ASSERT(fpscr_controlled); return Inst(Opcode::FPU32ToDouble, a, Imm1(round_to_nearest)); } U128 IREmitter::FPVectorAdd(size_t esize, const U128& a, const U128& b) { switch (esize) { case 32: return Inst(Opcode::FPVectorAdd32, a, b); case 64: return Inst(Opcode::FPVectorAdd64, a, b); } UNREACHABLE(); return {}; } U128 IREmitter::FPVectorSub(size_t esize, const U128& a, const U128& b) { switch (esize) { case 32: return Inst(Opcode::FPVectorSub32, a, b); case 64: return Inst(Opcode::FPVectorSub64, a, b); } UNREACHABLE(); return {}; } void IREmitter::Breakpoint() { Inst(Opcode::Breakpoint); } void IREmitter::SetTerm(const Terminal& terminal) { block.SetTerminal(terminal); } void IREmitter::SetInsertionPoint(IR::Inst* new_insertion_point) { insertion_point = IR::Block::iterator{*new_insertion_point}; } void IREmitter::SetInsertionPoint(IR::Block::iterator new_insertion_point) { insertion_point = new_insertion_point; } } // namespace Dynarmic::IR