You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

661 lines
22 KiB

/* This file is part of the dynarmic project.
* Copyright (c) 2016 MerryMage
* SPDX-License-Identifier: 0BSD
*/
#pragma once
#include <string>
#include <fmt/format.h>
#include <mcl/stdint.hpp>
namespace Dynarmic::IR {
enum class Type;
/// @brief The Opcodes of our intermediate representation.
/// Type signatures for each opcode can be found in opcodes.inc
enum class Opcode {
#define OPCODE(name, type, ...) name,
#define A32OPC(name, type, ...) A32##name,
#define A64OPC(name, type, ...) A64##name,
#include "./opcodes.inc"
#undef OPCODE
#undef A32OPC
#undef A64OPC
NUM_OPCODE
};
constexpr size_t OpcodeCount = static_cast<size_t>(Opcode::NUM_OPCODE);
Type GetTypeOf(Opcode op) noexcept;
size_t GetNumArgsOf(Opcode op) noexcept;
Type GetArgTypeOf(Opcode op, size_t arg_index) noexcept;
std::string GetNameOf(Opcode op) noexcept;
/// @brief Determines whether or not this instruction performs an arithmetic shift.
constexpr bool IsArithmeticShift(const Opcode op) noexcept {
return op == Opcode::ArithmeticShiftRight32
|| op == Opcode::ArithmeticShiftRight64;
}
/// @brief Determines whether or not this instruction performs a logical shift.
constexpr bool IsCircularShift(const Opcode op) noexcept {
return op == Opcode::RotateRight32
|| op == Opcode::RotateRight64
|| op == Opcode::RotateRightExtended;
}
/// @brief Determines whether or not this instruction performs a circular shift.
constexpr bool IsLogicalShift(const Opcode op) noexcept {
switch (op) {
case Opcode::LogicalShiftLeft32:
case Opcode::LogicalShiftLeft64:
case Opcode::LogicalShiftRight32:
case Opcode::LogicalShiftRight64:
return true;
default:
return false;
}
}
/// @brief Determines whether or not this instruction performs any kind of shift.
constexpr bool IsShift(const Opcode op) noexcept {
return IsArithmeticShift(op) || IsCircularShift(op) || IsLogicalShift(op);
}
/// @brief Determines whether or not this instruction is a form of barrier.
constexpr bool IsBarrier(const Opcode op) noexcept {
switch (op) {
case Opcode::A32DataMemoryBarrier:
case Opcode::A32DataSynchronizationBarrier:
case Opcode::A32InstructionSynchronizationBarrier:
case Opcode::A64DataMemoryBarrier:
case Opcode::A64DataSynchronizationBarrier:
case Opcode::A64InstructionSynchronizationBarrier:
return true;
default:
return false;
}
}
/// @brief Determines whether or not this instruction performs a shared memory read.
constexpr bool IsSharedMemoryRead(const Opcode op) noexcept {
switch (op) {
case Opcode::A32ReadMemory8:
case Opcode::A32ReadMemory16:
case Opcode::A32ReadMemory32:
case Opcode::A32ReadMemory64:
case Opcode::A64ReadMemory8:
case Opcode::A64ReadMemory16:
case Opcode::A64ReadMemory32:
case Opcode::A64ReadMemory64:
case Opcode::A64ReadMemory128:
return true;
default:
return false;
}
}
/// @brief Determines whether or not this instruction performs a shared memory write.
constexpr bool IsSharedMemoryWrite(const Opcode op) noexcept {
switch (op) {
case Opcode::A32WriteMemory8:
case Opcode::A32WriteMemory16:
case Opcode::A32WriteMemory32:
case Opcode::A32WriteMemory64:
case Opcode::A64WriteMemory8:
case Opcode::A64WriteMemory16:
case Opcode::A64WriteMemory32:
case Opcode::A64WriteMemory64:
case Opcode::A64WriteMemory128:
return true;
default:
return false;
}
}
/// @brief Determines whether or not this instruction performs a shared memory read or write.
constexpr bool IsSharedMemoryReadOrWrite(const Opcode op) noexcept {
return IsSharedMemoryRead(op) || IsSharedMemoryWrite(op);
}
/// @brief Determines whether or not this instruction performs an atomic memory read.
constexpr bool IsExclusiveMemoryRead(const Opcode op) noexcept {
switch (op) {
case Opcode::A32ExclusiveReadMemory8:
case Opcode::A32ExclusiveReadMemory16:
case Opcode::A32ExclusiveReadMemory32:
case Opcode::A32ExclusiveReadMemory64:
case Opcode::A64ExclusiveReadMemory8:
case Opcode::A64ExclusiveReadMemory16:
case Opcode::A64ExclusiveReadMemory32:
case Opcode::A64ExclusiveReadMemory64:
case Opcode::A64ExclusiveReadMemory128:
return true;
default:
return false;
}
}
/// @brief Determines whether or not this instruction performs an atomic memory write.
constexpr bool IsExclusiveMemoryWrite(const Opcode op) noexcept {
switch (op) {
case Opcode::A32ExclusiveWriteMemory8:
case Opcode::A32ExclusiveWriteMemory16:
case Opcode::A32ExclusiveWriteMemory32:
case Opcode::A32ExclusiveWriteMemory64:
case Opcode::A64ExclusiveWriteMemory8:
case Opcode::A64ExclusiveWriteMemory16:
case Opcode::A64ExclusiveWriteMemory32:
case Opcode::A64ExclusiveWriteMemory64:
case Opcode::A64ExclusiveWriteMemory128:
return true;
default:
return false;
}
}
/// @brief Determines whether or not this instruction performs any kind of memory read.
constexpr bool IsMemoryRead(const Opcode op) noexcept {
return IsSharedMemoryRead(op) || IsExclusiveMemoryRead(op);
}
/// @brief Determines whether or not this instruction performs any kind of memory write.
constexpr bool IsMemoryWrite(const Opcode op) noexcept {
return IsSharedMemoryWrite(op) || IsExclusiveMemoryWrite(op);
}
/// @brief Determines whether or not this instruction performs any kind of memory access.
constexpr bool IsMemoryReadOrWrite(const Opcode op) noexcept {
return IsMemoryRead(op) || IsMemoryWrite(op);
}
/// @brief Determines whether or not this instruction reads from the CPSR.
constexpr bool ReadsFromCPSR(const Opcode op) noexcept {
switch (op) {
case Opcode::A32GetCpsr:
case Opcode::A32GetCFlag:
case Opcode::A32GetGEFlags:
case Opcode::A32UpdateUpperLocationDescriptor:
case Opcode::A64GetCFlag:
case Opcode::A64GetNZCVRaw:
case Opcode::ConditionalSelect32:
case Opcode::ConditionalSelect64:
case Opcode::ConditionalSelectNZCV:
return true;
default:
return false;
}
}
/// @brief Determines whether or not this instruction writes to the CPSR.
constexpr bool WritesToCPSR(const Opcode op) noexcept {
switch (op) {
case Opcode::A32SetCpsr:
case Opcode::A32SetCpsrNZCVRaw:
case Opcode::A32SetCpsrNZCV:
case Opcode::A32SetCpsrNZCVQ:
case Opcode::A32SetCpsrNZ:
case Opcode::A32SetCpsrNZC:
case Opcode::A32OrQFlag:
case Opcode::A32SetGEFlags:
case Opcode::A32SetGEFlagsCompressed:
case Opcode::A32UpdateUpperLocationDescriptor:
case Opcode::A64SetNZCVRaw:
case Opcode::A64SetNZCV:
return true;
default:
return false;
}
}
/// @brief Determines whether or not this instruction writes to a system register.
constexpr bool WritesToSystemRegister(const Opcode op) noexcept {
switch (op) {
case Opcode::A64SetTPIDR:
return true;
default:
return false;
}
}
/// @brief Determines whether or not this instruction reads from a core register.
constexpr bool ReadsFromCoreRegister(const Opcode op) noexcept {
switch (op) {
case Opcode::A32GetRegister:
case Opcode::A32GetExtendedRegister32:
case Opcode::A32GetExtendedRegister64:
case Opcode::A32GetVector:
case Opcode::A64GetW:
case Opcode::A64GetX:
case Opcode::A64GetS:
case Opcode::A64GetD:
case Opcode::A64GetQ:
case Opcode::A64GetSP:
return true;
default:
return false;
}
}
/// @brief Determines whether or not this instruction writes to a core register.
constexpr bool WritesToCoreRegister(const Opcode op) noexcept {
switch (op) {
case Opcode::A32SetRegister:
case Opcode::A32SetExtendedRegister32:
case Opcode::A32SetExtendedRegister64:
case Opcode::A32SetVector:
case Opcode::A32BXWritePC:
case Opcode::A64SetW:
case Opcode::A64SetX:
case Opcode::A64SetS:
case Opcode::A64SetD:
case Opcode::A64SetQ:
case Opcode::A64SetSP:
case Opcode::A64SetPC:
return true;
default:
return false;
}
}
/// @brief Determines whether or not this instruction reads from the FPCR.
constexpr bool ReadsFromFPCR(const Opcode op) noexcept {
switch (op) {
case Opcode::A32GetFpscr:
case Opcode::A32GetFpscrNZCV:
case Opcode::A64GetFPCR:
return true;
default:
return false;
}
}
/// @brief Determines whether or not this instruction writes to the FPCR.
constexpr bool WritesToFPCR(const Opcode op) noexcept {
switch (op) {
case Opcode::A32SetFpscr:
case Opcode::A32SetFpscrNZCV:
case Opcode::A64SetFPCR:
return true;
default:
return false;
}
}
/// @brief Determines whether or not this instruction both reads from and writes to the FPSR cumulative exception bits.
constexpr bool ReadsFromAndWritesToFPSRCumulativeExceptionBits(const Opcode op) noexcept {
switch (op) {
case Opcode::FPAdd32:
case Opcode::FPAdd64:
case Opcode::FPCompare32:
case Opcode::FPCompare64:
case Opcode::FPDiv32:
case Opcode::FPDiv64:
case Opcode::FPMax32:
case Opcode::FPMax64:
case Opcode::FPMaxNumeric32:
case Opcode::FPMaxNumeric64:
case Opcode::FPMin32:
case Opcode::FPMin64:
case Opcode::FPMinNumeric32:
case Opcode::FPMinNumeric64:
case Opcode::FPMul32:
case Opcode::FPMul64:
case Opcode::FPMulAdd16:
case Opcode::FPMulAdd32:
case Opcode::FPMulAdd64:
case Opcode::FPMulSub16:
case Opcode::FPMulSub32:
case Opcode::FPMulSub64:
case Opcode::FPRecipEstimate16:
case Opcode::FPRecipEstimate32:
case Opcode::FPRecipEstimate64:
case Opcode::FPRecipExponent16:
case Opcode::FPRecipExponent32:
case Opcode::FPRecipExponent64:
case Opcode::FPRecipStepFused16:
case Opcode::FPRecipStepFused32:
case Opcode::FPRecipStepFused64:
case Opcode::FPRoundInt16:
case Opcode::FPRoundInt32:
case Opcode::FPRoundInt64:
case Opcode::FPRSqrtEstimate16:
case Opcode::FPRSqrtEstimate32:
case Opcode::FPRSqrtEstimate64:
case Opcode::FPRSqrtStepFused16:
case Opcode::FPRSqrtStepFused32:
case Opcode::FPRSqrtStepFused64:
case Opcode::FPSqrt32:
case Opcode::FPSqrt64:
case Opcode::FPSub32:
case Opcode::FPSub64:
case Opcode::FPHalfToDouble:
case Opcode::FPHalfToSingle:
case Opcode::FPSingleToDouble:
case Opcode::FPSingleToHalf:
case Opcode::FPDoubleToHalf:
case Opcode::FPDoubleToSingle:
case Opcode::FPDoubleToFixedS32:
case Opcode::FPDoubleToFixedS64:
case Opcode::FPDoubleToFixedU32:
case Opcode::FPDoubleToFixedU64:
case Opcode::FPHalfToFixedS32:
case Opcode::FPHalfToFixedS64:
case Opcode::FPHalfToFixedU32:
case Opcode::FPHalfToFixedU64:
case Opcode::FPSingleToFixedS32:
case Opcode::FPSingleToFixedS64:
case Opcode::FPSingleToFixedU32:
case Opcode::FPSingleToFixedU64:
case Opcode::FPFixedU32ToSingle:
case Opcode::FPFixedS32ToSingle:
case Opcode::FPFixedU32ToDouble:
case Opcode::FPFixedU64ToDouble:
case Opcode::FPFixedU64ToSingle:
case Opcode::FPFixedS32ToDouble:
case Opcode::FPFixedS64ToDouble:
case Opcode::FPFixedS64ToSingle:
case Opcode::FPVectorAdd32:
case Opcode::FPVectorAdd64:
case Opcode::FPVectorDiv32:
case Opcode::FPVectorDiv64:
case Opcode::FPVectorEqual16:
case Opcode::FPVectorEqual32:
case Opcode::FPVectorEqual64:
case Opcode::FPVectorFromSignedFixed32:
case Opcode::FPVectorFromSignedFixed64:
case Opcode::FPVectorFromUnsignedFixed32:
case Opcode::FPVectorFromUnsignedFixed64:
case Opcode::FPVectorGreater32:
case Opcode::FPVectorGreater64:
case Opcode::FPVectorGreaterEqual32:
case Opcode::FPVectorGreaterEqual64:
case Opcode::FPVectorMul32:
case Opcode::FPVectorMul64:
case Opcode::FPVectorMulAdd16:
case Opcode::FPVectorMulAdd32:
case Opcode::FPVectorMulAdd64:
case Opcode::FPVectorPairedAddLower32:
case Opcode::FPVectorPairedAddLower64:
case Opcode::FPVectorPairedAdd32:
case Opcode::FPVectorPairedAdd64:
case Opcode::FPVectorRecipEstimate16:
case Opcode::FPVectorRecipEstimate32:
case Opcode::FPVectorRecipEstimate64:
case Opcode::FPVectorRecipStepFused16:
case Opcode::FPVectorRecipStepFused32:
case Opcode::FPVectorRecipStepFused64:
case Opcode::FPVectorRoundInt16:
case Opcode::FPVectorRoundInt32:
case Opcode::FPVectorRoundInt64:
case Opcode::FPVectorRSqrtEstimate16:
case Opcode::FPVectorRSqrtEstimate32:
case Opcode::FPVectorRSqrtEstimate64:
case Opcode::FPVectorRSqrtStepFused16:
case Opcode::FPVectorRSqrtStepFused32:
case Opcode::FPVectorRSqrtStepFused64:
case Opcode::FPVectorSqrt32:
case Opcode::FPVectorSqrt64:
case Opcode::FPVectorSub32:
case Opcode::FPVectorSub64:
case Opcode::FPVectorToSignedFixed16:
case Opcode::FPVectorToSignedFixed32:
case Opcode::FPVectorToSignedFixed64:
case Opcode::FPVectorToUnsignedFixed16:
case Opcode::FPVectorToUnsignedFixed32:
case Opcode::FPVectorToUnsignedFixed64:
return true;
default:
return false;
}
}
/// @brief Determines whether or not this instruction reads from the FPSR cumulative saturation bit.
constexpr bool ReadsFromFPSRCumulativeSaturationBit([[maybe_unused]] const Opcode op) noexcept {
return false;
}
/// @brief Determines whether or not this instruction writes to the FPSR cumulative saturation bit.
constexpr bool ReadsFromFPSRCumulativeExceptionBits(const Opcode op) noexcept {
return ReadsFromAndWritesToFPSRCumulativeExceptionBits(op);
}
/// @brief Determines whether or not this instruction writes to the FPSR cumulative exception bits.
constexpr bool WritesToFPSRCumulativeExceptionBits(const Opcode op) noexcept {
return ReadsFromAndWritesToFPSRCumulativeExceptionBits(op);
}
/// @brief Determines whether or not this instruction writes to the FPSR cumulative saturation bit.
constexpr bool WritesToFPSRCumulativeSaturationBit(const Opcode op) noexcept {
switch (op) {
case Opcode::SignedSaturatedAdd8:
case Opcode::SignedSaturatedAdd16:
case Opcode::SignedSaturatedAdd32:
case Opcode::SignedSaturatedAdd64:
case Opcode::SignedSaturatedDoublingMultiplyReturnHigh16:
case Opcode::SignedSaturatedDoublingMultiplyReturnHigh32:
case Opcode::SignedSaturatedSub8:
case Opcode::SignedSaturatedSub16:
case Opcode::SignedSaturatedSub32:
case Opcode::SignedSaturatedSub64:
case Opcode::UnsignedSaturatedAdd8:
case Opcode::UnsignedSaturatedAdd16:
case Opcode::UnsignedSaturatedAdd32:
case Opcode::UnsignedSaturatedAdd64:
case Opcode::UnsignedSaturatedSub8:
case Opcode::UnsignedSaturatedSub16:
case Opcode::UnsignedSaturatedSub32:
case Opcode::UnsignedSaturatedSub64:
case Opcode::VectorSignedSaturatedAbs8:
case Opcode::VectorSignedSaturatedAbs16:
case Opcode::VectorSignedSaturatedAbs32:
case Opcode::VectorSignedSaturatedAbs64:
case Opcode::VectorSignedSaturatedAccumulateUnsigned8:
case Opcode::VectorSignedSaturatedAccumulateUnsigned16:
case Opcode::VectorSignedSaturatedAccumulateUnsigned32:
case Opcode::VectorSignedSaturatedAccumulateUnsigned64:
case Opcode::VectorSignedSaturatedAdd8:
case Opcode::VectorSignedSaturatedAdd16:
case Opcode::VectorSignedSaturatedAdd32:
case Opcode::VectorSignedSaturatedAdd64:
case Opcode::VectorSignedSaturatedDoublingMultiplyHigh16:
case Opcode::VectorSignedSaturatedDoublingMultiplyHigh32:
case Opcode::VectorSignedSaturatedDoublingMultiplyHighRounding16:
case Opcode::VectorSignedSaturatedDoublingMultiplyHighRounding32:
case Opcode::VectorSignedSaturatedDoublingMultiplyLong16:
case Opcode::VectorSignedSaturatedDoublingMultiplyLong32:
case Opcode::VectorSignedSaturatedNarrowToSigned16:
case Opcode::VectorSignedSaturatedNarrowToSigned32:
case Opcode::VectorSignedSaturatedNarrowToSigned64:
case Opcode::VectorSignedSaturatedNarrowToUnsigned16:
case Opcode::VectorSignedSaturatedNarrowToUnsigned32:
case Opcode::VectorSignedSaturatedNarrowToUnsigned64:
case Opcode::VectorSignedSaturatedNeg8:
case Opcode::VectorSignedSaturatedNeg16:
case Opcode::VectorSignedSaturatedNeg32:
case Opcode::VectorSignedSaturatedNeg64:
case Opcode::VectorSignedSaturatedShiftLeft8:
case Opcode::VectorSignedSaturatedShiftLeft16:
case Opcode::VectorSignedSaturatedShiftLeft32:
case Opcode::VectorSignedSaturatedShiftLeft64:
case Opcode::VectorSignedSaturatedShiftLeftUnsigned8:
case Opcode::VectorSignedSaturatedShiftLeftUnsigned16:
case Opcode::VectorSignedSaturatedShiftLeftUnsigned32:
case Opcode::VectorSignedSaturatedShiftLeftUnsigned64:
case Opcode::VectorSignedSaturatedSub8:
case Opcode::VectorSignedSaturatedSub16:
case Opcode::VectorSignedSaturatedSub32:
case Opcode::VectorSignedSaturatedSub64:
case Opcode::VectorUnsignedSaturatedAccumulateSigned8:
case Opcode::VectorUnsignedSaturatedAccumulateSigned16:
case Opcode::VectorUnsignedSaturatedAccumulateSigned32:
case Opcode::VectorUnsignedSaturatedAccumulateSigned64:
case Opcode::VectorUnsignedSaturatedAdd8:
case Opcode::VectorUnsignedSaturatedAdd16:
case Opcode::VectorUnsignedSaturatedAdd32:
case Opcode::VectorUnsignedSaturatedAdd64:
case Opcode::VectorUnsignedSaturatedNarrow16:
case Opcode::VectorUnsignedSaturatedNarrow32:
case Opcode::VectorUnsignedSaturatedNarrow64:
case Opcode::VectorUnsignedSaturatedShiftLeft8:
case Opcode::VectorUnsignedSaturatedShiftLeft16:
case Opcode::VectorUnsignedSaturatedShiftLeft32:
case Opcode::VectorUnsignedSaturatedShiftLeft64:
case Opcode::VectorUnsignedSaturatedSub8:
case Opcode::VectorUnsignedSaturatedSub16:
case Opcode::VectorUnsignedSaturatedSub32:
case Opcode::VectorUnsignedSaturatedSub64:
return true;
default:
return false;
}
}
/// @brief Determines whether or not this instruction reads from the FPSR.
constexpr bool ReadsFromFPSR(const Opcode op) noexcept {
return op == Opcode::A32GetFpscr
|| op == Opcode::A32GetFpscrNZCV
|| op == Opcode::A64GetFPSR
|| ReadsFromFPSRCumulativeExceptionBits(op)
|| ReadsFromFPSRCumulativeSaturationBit(op);
}
/// @brief Determines whether or not this instruction writes to the FPSR.
constexpr bool WritesToFPSR(const Opcode op) noexcept {
return op == Opcode::A32SetFpscr
|| op == Opcode::A32SetFpscrNZCV
|| op == Opcode::A64SetFPSR
|| WritesToFPSRCumulativeExceptionBits(op)
|| WritesToFPSRCumulativeSaturationBit(op);
}
/// @brief Determines whether or not this instruction causes a CPU exception.
constexpr bool CausesCPUException(const Opcode op) noexcept {
return op == Opcode::Breakpoint
|| op == Opcode::A32CallSupervisor
|| op == Opcode::A32ExceptionRaised
|| op == Opcode::A64CallSupervisor
|| op == Opcode::A64ExceptionRaised;
}
/// @brief Determines whether or not this instruction alters memory-exclusivity.
constexpr bool AltersExclusiveState(const Opcode op) noexcept {
return op == Opcode::A32ClearExclusive
|| op == Opcode::A64ClearExclusive
|| IsExclusiveMemoryRead(op)
|| IsExclusiveMemoryWrite(op);
}
/// @brief Determines whether or not this instruction accesses a coprocessor.
constexpr bool IsCoprocessorInstruction(const Opcode op) noexcept {
switch (op) {
case Opcode::A32CoprocInternalOperation:
case Opcode::A32CoprocSendOneWord:
case Opcode::A32CoprocSendTwoWords:
case Opcode::A32CoprocGetOneWord:
case Opcode::A32CoprocGetTwoWords:
case Opcode::A32CoprocLoadWords:
case Opcode::A32CoprocStoreWords:
return true;
default:
return false;
}
}
/// @brief Determines whether or not this instruction is a SetCheckBit operation.
constexpr bool IsSetCheckBitOperation(const Opcode op) noexcept {
return op == Opcode::A32SetCheckBit
|| op == Opcode::A64SetCheckBit;
}
/// @brief Determines whether or not this instruction may have side-effects.
constexpr bool MayHaveSideEffects(const Opcode op) noexcept {
return op == Opcode::PushRSB
|| op == Opcode::CallHostFunction
|| op == Opcode::A64DataCacheOperationRaised
|| op == Opcode::A64InstructionCacheOperationRaised
|| IsSetCheckBitOperation(op)
|| IsBarrier(op)
|| CausesCPUException(op)
|| WritesToCoreRegister(op)
|| WritesToSystemRegister(op)
|| WritesToCPSR(op)
|| WritesToFPCR(op)
|| WritesToFPSR(op)
|| AltersExclusiveState(op)
|| IsMemoryWrite(op)
|| IsCoprocessorInstruction(op);
}
/// @brief Determines whether or not this instruction is a pseduo-instruction.
/// @note Pseudo-instructions depend on their parent instructions for their semantics.
constexpr bool IsAPseudoOperation(const Opcode op) noexcept {
switch (op) {
case Opcode::GetCarryFromOp:
case Opcode::GetOverflowFromOp:
case Opcode::GetGEFromOp:
case Opcode::GetNZCVFromOp:
case Opcode::GetNZFromOp:
case Opcode::GetUpperFromOp:
case Opcode::GetLowerFromOp:
case Opcode::MostSignificantBit:
case Opcode::IsZero32:
case Opcode::IsZero64:
return true;
default:
return false;
}
}
/// @brief Determines whether or not this instruction supports the GetNZCVFromOp pseudo-operation.
constexpr bool MayGetNZCVFromOp(const Opcode op) noexcept {
switch (op) {
case Opcode::Add32:
case Opcode::Add64:
case Opcode::Sub32:
case Opcode::Sub64:
case Opcode::And32:
case Opcode::And64:
case Opcode::AndNot32:
case Opcode::AndNot64:
case Opcode::Eor32:
case Opcode::Eor64:
case Opcode::Or32:
case Opcode::Or64:
case Opcode::Not32:
case Opcode::Not64:
return true;
default:
return false;
}
}
} // namespace Dynarmic::IR
template<>
struct fmt::formatter<Dynarmic::IR::Opcode> : fmt::formatter<std::string> {
template<typename FormatContext>
auto format(Dynarmic::IR::Opcode op, FormatContext& ctx) const {
return formatter<std::string>::format(Dynarmic::IR::GetNameOf(op), ctx);
}
};