/* 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 { namespace IR { void IREmitter::Unimplemented() { } U1 IREmitter::Imm1(bool imm1) { return U1(Value(imm1)); } U8 IREmitter::Imm8(u8 imm8) { return U8(Value(imm8)); } 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); } 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(const U32& value) { return Inst(Opcode::LeastSignificantHalf, value); } U8 IREmitter::LeastSignificantByte(const U32& 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::IsZero, value); } U1 IREmitter::IsZero64(const U64& value) { return Inst(Opcode::IsZero64, 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}; } 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 Value& a, const Value& b, const U1& carry_in) { auto result = Inst(Opcode::AddWithCarry, a, b, carry_in); auto carry_out = Inst(Opcode::GetCarryFromOp, result); auto overflow = Inst(Opcode::GetOverflowFromOp, result); return {result, carry_out, overflow}; } U32 IREmitter::Add(const U32& a, const U32& b) { return Inst(Opcode::AddWithCarry, a, b, Imm1(0)); } U64 IREmitter::Add(const U64& a, const U64& b) { return Inst(Opcode::Add64, a, b); } U32U64 IREmitter::Add(const U32U64& a, const U32U64& b) { ASSERT(a.GetType() == b.GetType()); if (a.GetType() == Type::U32) { return Inst(Opcode::AddWithCarry, a, b, Imm1(0)); } else { return Inst(Opcode::Add64, a, b); } } 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::SubWithCarry, a, b, carry_in); auto carry_out = Inst(Opcode::GetCarryFromOp, result); auto overflow = Inst(Opcode::GetOverflowFromOp, result); return {result, carry_out, overflow}; } U32 IREmitter::Sub(const U32& a, const U32& b) { return Inst(Opcode::SubWithCarry, a, b, Imm1(1)); } U64 IREmitter::Sub(const U64& a, const U64& b) { return Inst(Opcode::Sub64, a, b); } U32 IREmitter::Mul(const U32& a, const U32& b) { return Inst(Opcode::Mul, a, b); } U64 IREmitter::Mul(const U64& a, const U64& b) { return Inst(Opcode::Mul64, a, b); } U32 IREmitter::And(const U32& a, const U32& b) { return Inst(Opcode::And, a, b); } U32 IREmitter::Eor(const U32& a, const U32& b) { return Inst(Opcode::Eor, a, b); } U32 IREmitter::Or(const U32& a, const U32& b) { return Inst(Opcode::Or, a, b); } U32 IREmitter::Not(const U32& a) { return Inst(Opcode::Not, a); } 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::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::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::CountLeadingZeros, a); } 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); } F32 IREmitter::TransferToFP32(const U32& a) { return Inst(Opcode::TransferToFP32, a); } F64 IREmitter::TransferToFP64(const U64& a) { return Inst(Opcode::TransferToFP64, a); } U32 IREmitter::TransferFromFP32(const F32& a) { return Inst(Opcode::TransferFromFP32, a); } U64 IREmitter::TransferFromFP64(const F64& a) { return Inst(Opcode::TransferFromFP64, a); } F32 IREmitter::FPAbs32(const F32& a) { return Inst(Opcode::FPAbs32, a); } F64 IREmitter::FPAbs64(const F64& a) { return Inst(Opcode::FPAbs64, a); } F32 IREmitter::FPAdd32(const F32& a, const F32& b, bool fpscr_controlled) { ASSERT(fpscr_controlled); return Inst(Opcode::FPAdd32, a, b); } F64 IREmitter::FPAdd64(const F64& a, const F64& b, bool fpscr_controlled) { ASSERT(fpscr_controlled); return Inst(Opcode::FPAdd64, a, b); } void IREmitter::FPCompare32(const F32& a, const F32& b, bool exc_on_qnan, bool fpscr_controlled) { ASSERT(fpscr_controlled); Inst(Opcode::FPCompare32, a, b, Imm1(exc_on_qnan)); } void IREmitter::FPCompare64(const F64& a, const F64& b, bool exc_on_qnan, bool fpscr_controlled) { ASSERT(fpscr_controlled); Inst(Opcode::FPCompare64, a, b, Imm1(exc_on_qnan)); } F32 IREmitter::FPDiv32(const F32& a, const F32& b, bool fpscr_controlled) { ASSERT(fpscr_controlled); return Inst(Opcode::FPDiv32, a, b); } F64 IREmitter::FPDiv64(const F64& a, const F64& b, bool fpscr_controlled) { ASSERT(fpscr_controlled); return Inst(Opcode::FPDiv64, a, b); } F32 IREmitter::FPMul32(const F32& a, const F32& b, bool fpscr_controlled) { ASSERT(fpscr_controlled); return Inst(Opcode::FPMul32, a, b); } F64 IREmitter::FPMul64(const F64& a, const F64& b, bool fpscr_controlled) { ASSERT(fpscr_controlled); return Inst(Opcode::FPMul64, a, b); } F32 IREmitter::FPNeg32(const F32& a) { return Inst(Opcode::FPNeg32, a); } F64 IREmitter::FPNeg64(const F64& a) { return Inst(Opcode::FPNeg64, a); } F32 IREmitter::FPSqrt32(const F32& a) { return Inst(Opcode::FPSqrt32, a); } F64 IREmitter::FPSqrt64(const F64& a) { return Inst(Opcode::FPSqrt64, a); } F32 IREmitter::FPSub32(const F32& a, const F32& b, bool fpscr_controlled) { ASSERT(fpscr_controlled); return Inst(Opcode::FPSub32, a, b); } F64 IREmitter::FPSub64(const F64& a, const F64& b, bool fpscr_controlled) { ASSERT(fpscr_controlled); return Inst(Opcode::FPSub64, a, b); } F32 IREmitter::FPDoubleToSingle(const F64& a, bool fpscr_controlled) { ASSERT(fpscr_controlled); return Inst(Opcode::FPDoubleToSingle, a); } F64 IREmitter::FPSingleToDouble(const F32& a, bool fpscr_controlled) { ASSERT(fpscr_controlled); return Inst(Opcode::FPSingleToDouble, a); } F32 IREmitter::FPSingleToS32(const F32& a, bool round_towards_zero, bool fpscr_controlled) { ASSERT(fpscr_controlled); return Inst(Opcode::FPSingleToS32, a, Imm1(round_towards_zero)); } F32 IREmitter::FPSingleToU32(const F32& a, bool round_towards_zero, bool fpscr_controlled) { ASSERT(fpscr_controlled); return Inst(Opcode::FPSingleToU32, a, Imm1(round_towards_zero)); } F32 IREmitter::FPDoubleToS32(const F32& a, bool round_towards_zero, bool fpscr_controlled) { ASSERT(fpscr_controlled); return Inst(Opcode::FPDoubleToS32, a, Imm1(round_towards_zero)); } F32 IREmitter::FPDoubleToU32(const F32& a, bool round_towards_zero, bool fpscr_controlled) { ASSERT(fpscr_controlled); return Inst(Opcode::FPDoubleToU32, a, Imm1(round_towards_zero)); } F32 IREmitter::FPS32ToSingle(const F32& a, bool round_to_nearest, bool fpscr_controlled) { ASSERT(fpscr_controlled); return Inst(Opcode::FPS32ToSingle, a, Imm1(round_to_nearest)); } F32 IREmitter::FPU32ToSingle(const F32& a, bool round_to_nearest, bool fpscr_controlled) { ASSERT(fpscr_controlled); return Inst(Opcode::FPU32ToSingle, a, Imm1(round_to_nearest)); } F64 IREmitter::FPS32ToDouble(const F32& a, bool round_to_nearest, bool fpscr_controlled) { ASSERT(fpscr_controlled); return Inst(Opcode::FPS32ToDouble, a, Imm1(round_to_nearest)); } F64 IREmitter::FPU32ToDouble(const F32& a, bool round_to_nearest, bool fpscr_controlled) { ASSERT(fpscr_controlled); return Inst(Opcode::FPU32ToDouble, a, Imm1(round_to_nearest)); } void IREmitter::Breakpoint() { Inst(Opcode::Breakpoint); } void IREmitter::SetTerm(const Terminal& terminal) { block.SetTerminal(terminal); } } // namespace IR } // namespace Dynarmic