2016-08-17 15:53:36 +01:00
|
|
|
/* 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.
|
|
|
|
*/
|
|
|
|
|
2017-01-29 22:54:54 +00:00
|
|
|
#include <algorithm>
|
|
|
|
|
2016-08-17 15:53:36 +01:00
|
|
|
#include "common/assert.h"
|
|
|
|
#include "frontend/ir/microinstruction.h"
|
2018-02-11 11:46:18 +00:00
|
|
|
#include "frontend/ir/opcodes.h"
|
|
|
|
#include "frontend/ir/type.h"
|
2016-08-17 15:53:36 +01:00
|
|
|
|
2018-01-26 13:51:48 +00:00
|
|
|
namespace Dynarmic::IR {
|
2016-08-17 15:53:36 +01:00
|
|
|
|
2016-08-22 17:54:47 +01:00
|
|
|
bool Inst::IsArithmeticShift() const {
|
2018-01-07 00:11:57 +00:00
|
|
|
return op == Opcode::ArithmeticShiftRight32 ||
|
|
|
|
op == Opcode::ArithmeticShiftRight64;
|
2016-08-22 17:54:47 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool Inst::IsCircularShift() const {
|
2018-01-07 00:11:57 +00:00
|
|
|
return op == Opcode::RotateRight32 ||
|
|
|
|
op == Opcode::RotateRight64 ||
|
2016-08-22 17:54:47 +01:00
|
|
|
op == Opcode::RotateRightExtended;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Inst::IsLogicalShift() const {
|
|
|
|
switch (op) {
|
2018-01-07 00:11:57 +00:00
|
|
|
case Opcode::LogicalShiftLeft32:
|
|
|
|
case Opcode::LogicalShiftLeft64:
|
|
|
|
case Opcode::LogicalShiftRight32:
|
2016-08-22 17:54:47 +01:00
|
|
|
case Opcode::LogicalShiftRight64:
|
|
|
|
return true;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Inst::IsShift() const {
|
|
|
|
return IsArithmeticShift() ||
|
|
|
|
IsCircularShift() ||
|
|
|
|
IsLogicalShift();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Inst::IsSharedMemoryRead() const {
|
|
|
|
switch (op) {
|
2018-01-01 16:19:43 +00:00
|
|
|
case Opcode::A32ReadMemory8:
|
|
|
|
case Opcode::A32ReadMemory16:
|
|
|
|
case Opcode::A32ReadMemory32:
|
|
|
|
case Opcode::A32ReadMemory64:
|
2018-01-10 01:13:23 +00:00
|
|
|
case Opcode::A64ReadMemory8:
|
|
|
|
case Opcode::A64ReadMemory16:
|
|
|
|
case Opcode::A64ReadMemory32:
|
|
|
|
case Opcode::A64ReadMemory64:
|
2018-01-25 23:56:14 +00:00
|
|
|
case Opcode::A64ReadMemory128:
|
2016-08-22 17:54:47 +01:00
|
|
|
return true;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Inst::IsSharedMemoryWrite() const {
|
|
|
|
switch (op) {
|
2018-01-01 16:19:43 +00:00
|
|
|
case Opcode::A32WriteMemory8:
|
|
|
|
case Opcode::A32WriteMemory16:
|
|
|
|
case Opcode::A32WriteMemory32:
|
|
|
|
case Opcode::A32WriteMemory64:
|
2018-01-10 01:13:23 +00:00
|
|
|
case Opcode::A64WriteMemory8:
|
|
|
|
case Opcode::A64WriteMemory16:
|
|
|
|
case Opcode::A64WriteMemory32:
|
|
|
|
case Opcode::A64WriteMemory64:
|
2018-01-25 23:56:14 +00:00
|
|
|
case Opcode::A64WriteMemory128:
|
2016-08-22 17:54:47 +01:00
|
|
|
return true;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Inst::IsSharedMemoryReadOrWrite() const {
|
|
|
|
return IsSharedMemoryRead() || IsSharedMemoryWrite();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Inst::IsExclusiveMemoryWrite() const {
|
|
|
|
switch (op) {
|
2018-01-01 16:19:43 +00:00
|
|
|
case Opcode::A32ExclusiveWriteMemory8:
|
|
|
|
case Opcode::A32ExclusiveWriteMemory16:
|
|
|
|
case Opcode::A32ExclusiveWriteMemory32:
|
|
|
|
case Opcode::A32ExclusiveWriteMemory64:
|
A64: Implement STXRB, STXRH, STXR, STLXRB, STLXRH, STLXR, LDXRB, LDXRH, LDXR, LDAXRB, LDAXRH, LDAXR
2018-02-13 00:19:04 +00:00
|
|
|
case Opcode::A64ExclusiveWriteMemory8:
|
|
|
|
case Opcode::A64ExclusiveWriteMemory16:
|
|
|
|
case Opcode::A64ExclusiveWriteMemory32:
|
|
|
|
case Opcode::A64ExclusiveWriteMemory64:
|
|
|
|
case Opcode::A64ExclusiveWriteMemory128:
|
2016-08-22 17:54:47 +01:00
|
|
|
return true;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Inst::IsMemoryRead() const {
|
|
|
|
return IsSharedMemoryRead();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Inst::IsMemoryWrite() const {
|
|
|
|
return IsSharedMemoryWrite() || IsExclusiveMemoryWrite();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Inst::IsMemoryReadOrWrite() const {
|
|
|
|
return IsMemoryRead() || IsMemoryWrite();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Inst::ReadsFromCPSR() const {
|
|
|
|
switch (op) {
|
2018-01-01 16:19:43 +00:00
|
|
|
case Opcode::A32GetCpsr:
|
|
|
|
case Opcode::A32GetNFlag:
|
|
|
|
case Opcode::A32GetZFlag:
|
|
|
|
case Opcode::A32GetCFlag:
|
|
|
|
case Opcode::A32GetVFlag:
|
|
|
|
case Opcode::A32GetGEFlags:
|
2018-01-26 23:37:54 +00:00
|
|
|
case Opcode::A64GetCFlag:
|
2018-01-23 17:45:14 +00:00
|
|
|
case Opcode::ConditionalSelect32:
|
|
|
|
case Opcode::ConditionalSelect64:
|
2018-02-05 00:38:47 +00:00
|
|
|
case Opcode::ConditionalSelectNZCV:
|
2016-08-22 17:54:47 +01:00
|
|
|
return true;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Inst::WritesToCPSR() const {
|
|
|
|
switch (op) {
|
2018-01-01 16:19:43 +00:00
|
|
|
case Opcode::A32SetCpsr:
|
|
|
|
case Opcode::A32SetCpsrNZCV:
|
|
|
|
case Opcode::A32SetCpsrNZCVQ:
|
|
|
|
case Opcode::A32SetNFlag:
|
|
|
|
case Opcode::A32SetZFlag:
|
|
|
|
case Opcode::A32SetCFlag:
|
|
|
|
case Opcode::A32SetVFlag:
|
|
|
|
case Opcode::A32OrQFlag:
|
|
|
|
case Opcode::A32SetGEFlags:
|
|
|
|
case Opcode::A32SetGEFlagsCompressed:
|
2018-01-07 14:46:35 +00:00
|
|
|
case Opcode::A64SetNZCV:
|
2016-08-22 17:54:47 +01:00
|
|
|
return true;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-21 02:20:20 +01:00
|
|
|
bool Inst::WritesToSystemRegister() const {
|
|
|
|
switch (op) {
|
|
|
|
case Opcode::A64SetTPIDR:
|
|
|
|
return true;
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-22 17:54:47 +01:00
|
|
|
bool Inst::ReadsFromCoreRegister() const {
|
|
|
|
switch (op) {
|
2018-01-01 16:19:43 +00:00
|
|
|
case Opcode::A32GetRegister:
|
|
|
|
case Opcode::A32GetExtendedRegister32:
|
|
|
|
case Opcode::A32GetExtendedRegister64:
|
2018-01-07 00:11:57 +00:00
|
|
|
case Opcode::A64GetW:
|
|
|
|
case Opcode::A64GetX:
|
2018-01-26 18:35:19 +00:00
|
|
|
case Opcode::A64GetS:
|
2018-01-23 17:45:14 +00:00
|
|
|
case Opcode::A64GetD:
|
|
|
|
case Opcode::A64GetQ:
|
2018-01-07 11:31:20 +00:00
|
|
|
case Opcode::A64GetSP:
|
2016-08-22 17:54:47 +01:00
|
|
|
return true;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Inst::WritesToCoreRegister() const {
|
|
|
|
switch (op) {
|
2018-01-01 16:19:43 +00:00
|
|
|
case Opcode::A32SetRegister:
|
|
|
|
case Opcode::A32SetExtendedRegister32:
|
|
|
|
case Opcode::A32SetExtendedRegister64:
|
|
|
|
case Opcode::A32BXWritePC:
|
2018-01-07 00:11:57 +00:00
|
|
|
case Opcode::A64SetW:
|
|
|
|
case Opcode::A64SetX:
|
2018-01-26 18:35:19 +00:00
|
|
|
case Opcode::A64SetS:
|
2018-01-23 17:45:14 +00:00
|
|
|
case Opcode::A64SetD:
|
|
|
|
case Opcode::A64SetQ:
|
2018-01-07 11:31:20 +00:00
|
|
|
case Opcode::A64SetSP:
|
2018-01-07 13:56:32 +00:00
|
|
|
case Opcode::A64SetPC:
|
2016-08-22 17:54:47 +01:00
|
|
|
return true;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-24 12:10:57 +01:00
|
|
|
bool Inst::ReadsFromFPCR() const {
|
2016-08-22 17:54:47 +01:00
|
|
|
switch (op) {
|
2018-01-01 16:19:43 +00:00
|
|
|
case Opcode::A32GetFpscr:
|
|
|
|
case Opcode::A32GetFpscrNZCV:
|
2018-02-20 17:38:29 +00:00
|
|
|
case Opcode::A64GetFPCR:
|
2016-08-22 17:54:47 +01:00
|
|
|
return true;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-24 12:10:57 +01:00
|
|
|
bool Inst::WritesToFPCR() const {
|
2016-08-22 17:54:47 +01:00
|
|
|
switch (op) {
|
2018-01-01 16:19:43 +00:00
|
|
|
case Opcode::A32SetFpscr:
|
|
|
|
case Opcode::A32SetFpscrNZCV:
|
2018-02-20 17:38:29 +00:00
|
|
|
case Opcode::A64SetFPCR:
|
2018-07-24 12:10:57 +01:00
|
|
|
return true;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Inst::ReadsFromFPSR() const {
|
|
|
|
return op == Opcode::A32GetFpscr ||
|
|
|
|
op == Opcode::A32GetFpscrNZCV ||
|
|
|
|
op == Opcode::A64GetFPSR ||
|
|
|
|
ReadsFromFPSRCumulativeExceptionBits() ||
|
|
|
|
ReadsFromFPSRCumulativeSaturationBit();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Inst::WritesToFPSR() const {
|
|
|
|
return op == Opcode::A32SetFpscr ||
|
|
|
|
op == Opcode::A32SetFpscrNZCV ||
|
|
|
|
op == Opcode::A64SetFPSR ||
|
|
|
|
WritesToFPSRCumulativeExceptionBits() ||
|
|
|
|
WritesToFPSRCumulativeSaturationBit();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Inst::ReadsFromFPSRCumulativeExceptionBits() const {
|
|
|
|
return ReadsFromAndWritesToFPSRCumulativeExceptionBits();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Inst::WritesToFPSRCumulativeExceptionBits() const {
|
|
|
|
return ReadsFromAndWritesToFPSRCumulativeExceptionBits();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Inst::ReadsFromAndWritesToFPSRCumulativeExceptionBits() const {
|
|
|
|
switch (op) {
|
2016-08-22 17:54:47 +01:00
|
|
|
case Opcode::FPAbs32:
|
|
|
|
case Opcode::FPAbs64:
|
|
|
|
case Opcode::FPAdd32:
|
|
|
|
case Opcode::FPAdd64:
|
2016-11-26 11:17:16 +00:00
|
|
|
case Opcode::FPCompare32:
|
|
|
|
case Opcode::FPCompare64:
|
2016-08-22 17:54:47 +01:00
|
|
|
case Opcode::FPDiv32:
|
|
|
|
case Opcode::FPDiv64:
|
2018-07-23 03:49:35 +01:00
|
|
|
case Opcode::FPMax32:
|
|
|
|
case Opcode::FPMax64:
|
|
|
|
case Opcode::FPMaxNumeric32:
|
|
|
|
case Opcode::FPMaxNumeric64:
|
|
|
|
case Opcode::FPMin32:
|
|
|
|
case Opcode::FPMin64:
|
|
|
|
case Opcode::FPMinNumeric32:
|
|
|
|
case Opcode::FPMinNumeric64:
|
2016-08-22 17:54:47 +01:00
|
|
|
case Opcode::FPMul32:
|
|
|
|
case Opcode::FPMul64:
|
2018-07-23 03:49:35 +01:00
|
|
|
case Opcode::FPMulAdd32:
|
|
|
|
case Opcode::FPMulAdd64:
|
2016-08-22 17:54:47 +01:00
|
|
|
case Opcode::FPNeg32:
|
|
|
|
case Opcode::FPNeg64:
|
2018-07-23 03:49:35 +01:00
|
|
|
case Opcode::FPRoundInt32:
|
|
|
|
case Opcode::FPRoundInt64:
|
|
|
|
case Opcode::FPRSqrtEstimate32:
|
|
|
|
case Opcode::FPRSqrtEstimate64:
|
2018-07-24 12:10:57 +01:00
|
|
|
case Opcode::FPRSqrtStepFused32:
|
|
|
|
case Opcode::FPRSqrtStepFused64:
|
|
|
|
case Opcode::FPSqrt32:
|
|
|
|
case Opcode::FPSqrt64:
|
2016-08-22 17:54:47 +01:00
|
|
|
case Opcode::FPSub32:
|
|
|
|
case Opcode::FPSub64:
|
2018-07-24 12:10:57 +01:00
|
|
|
case Opcode::FPSingleToDouble:
|
|
|
|
case Opcode::FPDoubleToSingle:
|
|
|
|
case Opcode::FPDoubleToFixedS32:
|
|
|
|
case Opcode::FPDoubleToFixedS64:
|
|
|
|
case Opcode::FPDoubleToFixedU32:
|
|
|
|
case Opcode::FPDoubleToFixedU64:
|
|
|
|
case Opcode::FPSingleToFixedS32:
|
|
|
|
case Opcode::FPSingleToFixedS64:
|
|
|
|
case Opcode::FPSingleToFixedU32:
|
|
|
|
case Opcode::FPSingleToFixedU64:
|
|
|
|
case Opcode::FPU32ToSingle:
|
|
|
|
case Opcode::FPS32ToSingle:
|
|
|
|
case Opcode::FPU32ToDouble:
|
|
|
|
case Opcode::FPU64ToDouble:
|
|
|
|
case Opcode::FPU64ToSingle:
|
|
|
|
case Opcode::FPS32ToDouble:
|
|
|
|
case Opcode::FPS64ToDouble:
|
|
|
|
case Opcode::FPS64ToSingle:
|
|
|
|
case Opcode::FPVectorAbs16:
|
|
|
|
case Opcode::FPVectorAbs32:
|
|
|
|
case Opcode::FPVectorAbs64:
|
|
|
|
case Opcode::FPVectorAdd32:
|
|
|
|
case Opcode::FPVectorAdd64:
|
|
|
|
case Opcode::FPVectorDiv32:
|
|
|
|
case Opcode::FPVectorDiv64:
|
|
|
|
case Opcode::FPVectorEqual32:
|
|
|
|
case Opcode::FPVectorEqual64:
|
|
|
|
case Opcode::FPVectorGreater32:
|
|
|
|
case Opcode::FPVectorGreater64:
|
|
|
|
case Opcode::FPVectorGreaterEqual32:
|
|
|
|
case Opcode::FPVectorGreaterEqual64:
|
|
|
|
case Opcode::FPVectorMul32:
|
|
|
|
case Opcode::FPVectorMul64:
|
|
|
|
case Opcode::FPVectorPairedAddLower32:
|
|
|
|
case Opcode::FPVectorPairedAddLower64:
|
|
|
|
case Opcode::FPVectorPairedAdd32:
|
|
|
|
case Opcode::FPVectorPairedAdd64:
|
|
|
|
case Opcode::FPVectorRSqrtEstimate32:
|
|
|
|
case Opcode::FPVectorRSqrtEstimate64:
|
|
|
|
case Opcode::FPVectorRSqrtStepFused32:
|
|
|
|
case Opcode::FPVectorRSqrtStepFused64:
|
|
|
|
case Opcode::FPVectorS32ToSingle:
|
|
|
|
case Opcode::FPVectorS64ToDouble:
|
|
|
|
case Opcode::FPVectorSub32:
|
|
|
|
case Opcode::FPVectorSub64:
|
|
|
|
case Opcode::FPVectorU32ToSingle:
|
|
|
|
case Opcode::FPVectorU64ToDouble:
|
2016-08-22 17:54:47 +01:00
|
|
|
return true;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-24 12:10:57 +01:00
|
|
|
bool Inst::ReadsFromFPSRCumulativeSaturationBit() const {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Inst::WritesToFPSRCumulativeSaturationBit() const {
|
2018-07-24 16:06:55 +01:00
|
|
|
switch (op) {
|
|
|
|
case Opcode::VectorSignedSaturatedNarrowToUnsigned16:
|
|
|
|
case Opcode::VectorSignedSaturatedNarrowToUnsigned32:
|
|
|
|
case Opcode::VectorSignedSaturatedNarrowToUnsigned64:
|
|
|
|
return true;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
2018-07-24 12:10:57 +01:00
|
|
|
}
|
|
|
|
|
2016-08-22 17:54:47 +01:00
|
|
|
bool Inst::CausesCPUException() const {
|
2018-01-08 22:03:03 +00:00
|
|
|
return op == Opcode::Breakpoint ||
|
|
|
|
op == Opcode::A32CallSupervisor ||
|
2018-01-13 17:54:29 +00:00
|
|
|
op == Opcode::A64CallSupervisor ||
|
|
|
|
op == Opcode::A64ExceptionRaised;
|
2016-08-22 17:54:47 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool Inst::AltersExclusiveState() const {
|
2018-01-01 16:19:43 +00:00
|
|
|
return op == Opcode::A32ClearExclusive ||
|
|
|
|
op == Opcode::A32SetExclusive ||
|
A64: Implement STXRB, STXRH, STXR, STLXRB, STLXRH, STLXR, LDXRB, LDXRH, LDXR, LDAXRB, LDAXRH, LDAXR
2018-02-13 00:19:04 +00:00
|
|
|
op == Opcode::A64ClearExclusive ||
|
|
|
|
op == Opcode::A64SetExclusive ||
|
2016-08-22 17:54:47 +01:00
|
|
|
IsExclusiveMemoryWrite();
|
|
|
|
}
|
|
|
|
|
2016-12-31 11:17:47 +00:00
|
|
|
bool Inst::IsCoprocessorInstruction() const {
|
|
|
|
switch (op) {
|
2018-01-01 16:19:43 +00:00
|
|
|
case Opcode::A32CoprocInternalOperation:
|
|
|
|
case Opcode::A32CoprocSendOneWord:
|
|
|
|
case Opcode::A32CoprocSendTwoWords:
|
|
|
|
case Opcode::A32CoprocGetOneWord:
|
|
|
|
case Opcode::A32CoprocGetTwoWords:
|
|
|
|
case Opcode::A32CoprocLoadWords:
|
|
|
|
case Opcode::A32CoprocStoreWords:
|
2016-12-31 11:17:47 +00:00
|
|
|
return true;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-22 17:54:47 +01:00
|
|
|
bool Inst::MayHaveSideEffects() const {
|
2018-02-11 22:53:46 +00:00
|
|
|
return op == Opcode::PushRSB ||
|
|
|
|
op == Opcode::A64SetCheckBit ||
|
|
|
|
op == Opcode::A64DataCacheOperationRaised ||
|
2018-02-11 23:27:28 +00:00
|
|
|
op == Opcode::A64DataSynchronizationBarrier ||
|
|
|
|
op == Opcode::A64DataMemoryBarrier ||
|
2018-02-11 22:53:46 +00:00
|
|
|
CausesCPUException() ||
|
|
|
|
WritesToCoreRegister() ||
|
2018-07-21 02:20:20 +01:00
|
|
|
WritesToSystemRegister() ||
|
2018-02-11 22:53:46 +00:00
|
|
|
WritesToCPSR() ||
|
2018-07-24 12:10:57 +01:00
|
|
|
WritesToFPCR() ||
|
|
|
|
WritesToFPSR() ||
|
2018-02-11 22:53:46 +00:00
|
|
|
AltersExclusiveState() ||
|
|
|
|
IsMemoryWrite() ||
|
2016-12-31 11:17:47 +00:00
|
|
|
IsCoprocessorInstruction();
|
2016-11-30 21:51:06 +00:00
|
|
|
}
|
2016-08-22 17:54:47 +01:00
|
|
|
|
2018-01-07 11:31:20 +00:00
|
|
|
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:
|
2018-01-07 12:52:12 +00:00
|
|
|
case Opcode::And32:
|
|
|
|
case Opcode::And64:
|
|
|
|
case Opcode::Eor32:
|
|
|
|
case Opcode::Eor64:
|
|
|
|
case Opcode::Or32:
|
|
|
|
case Opcode::Or64:
|
|
|
|
case Opcode::Not32:
|
|
|
|
case Opcode::Not64:
|
2018-01-07 11:31:20 +00:00
|
|
|
return true;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-29 22:54:54 +00:00
|
|
|
bool Inst::AreAllArgsImmediates() const {
|
|
|
|
return std::all_of(args.begin(), args.begin() + NumArgs(), [](const auto& value){ return value.IsImmediate(); });
|
|
|
|
}
|
|
|
|
|
2017-04-04 13:10:50 +01:00
|
|
|
bool Inst::HasAssociatedPseudoOperation() const {
|
2018-01-07 11:31:20 +00:00
|
|
|
return carry_inst || overflow_inst || ge_inst || nzcv_inst;
|
2017-04-04 13:10:50 +01:00
|
|
|
}
|
|
|
|
|
2016-08-25 21:08:47 +01:00
|
|
|
Inst* Inst::GetAssociatedPseudoOperation(Opcode opcode) {
|
|
|
|
// This is faster than doing a search through the block.
|
|
|
|
switch (opcode) {
|
2018-01-07 11:31:20 +00:00
|
|
|
case Opcode::GetCarryFromOp:
|
2017-02-26 23:27:41 +00:00
|
|
|
ASSERT(!carry_inst || carry_inst->GetOpcode() == Opcode::GetCarryFromOp);
|
2016-08-25 21:08:47 +01:00
|
|
|
return carry_inst;
|
2018-01-07 11:31:20 +00:00
|
|
|
case Opcode::GetOverflowFromOp:
|
2017-02-26 23:27:41 +00:00
|
|
|
ASSERT(!overflow_inst || overflow_inst->GetOpcode() == Opcode::GetOverflowFromOp);
|
2016-08-25 21:08:47 +01:00
|
|
|
return overflow_inst;
|
2018-01-07 11:31:20 +00:00
|
|
|
case Opcode::GetGEFromOp:
|
2017-02-26 23:27:41 +00:00
|
|
|
ASSERT(!ge_inst || ge_inst->GetOpcode() == Opcode::GetGEFromOp);
|
2016-12-04 20:52:06 +00:00
|
|
|
return ge_inst;
|
2018-01-07 11:31:20 +00:00
|
|
|
case Opcode::GetNZCVFromOp:
|
|
|
|
ASSERT(!nzcv_inst || nzcv_inst->GetOpcode() == Opcode::GetNZCVFromOp);
|
|
|
|
return nzcv_inst;
|
2016-08-25 21:08:47 +01:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
ASSERT_MSG(false, "Not a valid pseudo-operation");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2016-08-23 15:48:30 +01:00
|
|
|
Type Inst::GetType() const {
|
|
|
|
if (op == Opcode::Identity)
|
|
|
|
return args[0].GetType();
|
|
|
|
return GetTypeOf(op);
|
|
|
|
}
|
|
|
|
|
2018-02-11 11:46:18 +00:00
|
|
|
size_t Inst::NumArgs() const {
|
|
|
|
return GetNumArgsOf(op);
|
|
|
|
}
|
|
|
|
|
2016-08-17 15:53:36 +01:00
|
|
|
Value Inst::GetArg(size_t index) const {
|
2017-02-26 23:27:41 +00:00
|
|
|
ASSERT(index < GetNumArgsOf(op));
|
|
|
|
ASSERT(!args[index].IsEmpty());
|
2016-08-17 15:53:36 +01:00
|
|
|
|
|
|
|
return args[index];
|
|
|
|
}
|
|
|
|
|
|
|
|
void Inst::SetArg(size_t index, Value value) {
|
2017-02-26 23:27:41 +00:00
|
|
|
ASSERT(index < GetNumArgsOf(op));
|
|
|
|
ASSERT(AreTypesCompatible(value.GetType(), GetArgTypeOf(op, index)));
|
2016-08-17 15:53:36 +01:00
|
|
|
|
|
|
|
if (!args[index].IsImmediate()) {
|
|
|
|
UndoUse(args[index]);
|
|
|
|
}
|
|
|
|
if (!value.IsImmediate()) {
|
|
|
|
Use(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
args[index] = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Inst::Invalidate() {
|
2018-01-18 13:00:07 +00:00
|
|
|
ClearArgs();
|
|
|
|
op = Opcode::Void;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Inst::ClearArgs() {
|
2016-08-17 15:53:36 +01:00
|
|
|
for (auto& value : args) {
|
|
|
|
if (!value.IsImmediate()) {
|
|
|
|
UndoUse(value);
|
|
|
|
}
|
2017-02-18 21:29:23 +00:00
|
|
|
value = {};
|
2016-08-17 15:53:36 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-29 22:52:33 +00:00
|
|
|
void Inst::ReplaceUsesWith(Value replacement) {
|
2016-08-17 15:53:36 +01:00
|
|
|
Invalidate();
|
|
|
|
|
|
|
|
op = Opcode::Identity;
|
|
|
|
|
|
|
|
if (!replacement.IsImmediate()) {
|
|
|
|
Use(replacement);
|
|
|
|
}
|
|
|
|
|
|
|
|
args[0] = replacement;
|
|
|
|
}
|
|
|
|
|
2017-01-29 22:53:46 +00:00
|
|
|
void Inst::Use(const Value& value) {
|
2016-08-17 15:53:36 +01:00
|
|
|
value.GetInst()->use_count++;
|
|
|
|
|
|
|
|
switch (op){
|
2016-08-22 23:40:30 +01:00
|
|
|
case Opcode::GetCarryFromOp:
|
2016-08-25 21:08:47 +01:00
|
|
|
ASSERT_MSG(!value.GetInst()->carry_inst, "Only one of each type of pseudo-op allowed");
|
2016-08-22 23:40:30 +01:00
|
|
|
value.GetInst()->carry_inst = this;
|
|
|
|
break;
|
|
|
|
case Opcode::GetOverflowFromOp:
|
2016-08-25 21:08:47 +01:00
|
|
|
ASSERT_MSG(!value.GetInst()->overflow_inst, "Only one of each type of pseudo-op allowed");
|
2016-08-22 23:40:30 +01:00
|
|
|
value.GetInst()->overflow_inst = this;
|
|
|
|
break;
|
2016-12-04 20:52:06 +00:00
|
|
|
case Opcode::GetGEFromOp:
|
|
|
|
ASSERT_MSG(!value.GetInst()->ge_inst, "Only one of each type of pseudo-op allowed");
|
|
|
|
value.GetInst()->ge_inst = this;
|
|
|
|
break;
|
2018-01-07 11:31:20 +00:00
|
|
|
case Opcode::GetNZCVFromOp:
|
|
|
|
ASSERT_MSG(!value.GetInst()->nzcv_inst, "Only one of each type of pseudo-op allowed");
|
2018-01-07 14:46:35 +00:00
|
|
|
ASSERT_MSG(value.GetInst()->MayGetNZCVFromOp(), "This value doesn't support the GetNZCVFromOp pseduo-op");
|
2018-01-07 11:31:20 +00:00
|
|
|
value.GetInst()->nzcv_inst = this;
|
|
|
|
break;
|
2016-08-22 23:40:30 +01:00
|
|
|
default:
|
|
|
|
break;
|
2016-08-17 15:53:36 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-29 22:53:46 +00:00
|
|
|
void Inst::UndoUse(const Value& value) {
|
2016-08-17 15:53:36 +01:00
|
|
|
value.GetInst()->use_count--;
|
|
|
|
|
|
|
|
switch (op){
|
2016-08-22 23:40:30 +01:00
|
|
|
case Opcode::GetCarryFromOp:
|
2017-02-26 23:27:41 +00:00
|
|
|
ASSERT(value.GetInst()->carry_inst->GetOpcode() == Opcode::GetCarryFromOp);
|
2016-08-22 23:40:30 +01:00
|
|
|
value.GetInst()->carry_inst = nullptr;
|
|
|
|
break;
|
|
|
|
case Opcode::GetOverflowFromOp:
|
2017-02-26 23:27:41 +00:00
|
|
|
ASSERT(value.GetInst()->overflow_inst->GetOpcode() == Opcode::GetOverflowFromOp);
|
2016-08-22 23:40:30 +01:00
|
|
|
value.GetInst()->overflow_inst = nullptr;
|
|
|
|
break;
|
2016-12-04 20:52:06 +00:00
|
|
|
case Opcode::GetGEFromOp:
|
2017-02-26 23:27:41 +00:00
|
|
|
ASSERT(value.GetInst()->ge_inst->GetOpcode() == Opcode::GetGEFromOp);
|
2016-12-04 20:52:06 +00:00
|
|
|
value.GetInst()->ge_inst = nullptr;
|
|
|
|
break;
|
2018-01-07 11:31:20 +00:00
|
|
|
case Opcode::GetNZCVFromOp:
|
|
|
|
ASSERT(value.GetInst()->nzcv_inst->GetOpcode() == Opcode::GetNZCVFromOp);
|
|
|
|
value.GetInst()->nzcv_inst = nullptr;
|
|
|
|
break;
|
2016-08-22 23:40:30 +01:00
|
|
|
default:
|
|
|
|
break;
|
2016-08-17 15:53:36 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-26 13:51:48 +00:00
|
|
|
} // namespace Dynarmic::IR
|