dynarmic/src/frontend/ir/microinstruction.cpp

296 lines
6.1 KiB
C++
Raw Normal View History

/* 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/microinstruction.h"
namespace Dynarmic {
namespace IR {
bool Inst::IsArithmeticShift() const {
return op == Opcode::ArithmeticShiftRight;
}
bool Inst::IsCircularShift() const {
return op == Opcode::RotateRight ||
op == Opcode::RotateRightExtended;
}
bool Inst::IsLogicalShift() const {
switch (op) {
case Opcode::LogicalShiftLeft:
case Opcode::LogicalShiftRight:
case Opcode::LogicalShiftRight64:
return true;
default:
return false;
}
}
bool Inst::IsShift() const {
return IsArithmeticShift() ||
IsCircularShift() ||
IsLogicalShift();
}
bool Inst::IsSharedMemoryRead() const {
switch (op) {
case Opcode::ReadMemory8:
case Opcode::ReadMemory16:
case Opcode::ReadMemory32:
case Opcode::ReadMemory64:
return true;
default:
return false;
}
}
bool Inst::IsSharedMemoryWrite() const {
switch (op) {
case Opcode::WriteMemory8:
case Opcode::WriteMemory16:
case Opcode::WriteMemory32:
case Opcode::WriteMemory64:
return true;
default:
return false;
}
}
bool Inst::IsSharedMemoryReadOrWrite() const {
return IsSharedMemoryRead() || IsSharedMemoryWrite();
}
bool Inst::IsExclusiveMemoryWrite() const {
switch (op) {
case Opcode::ExclusiveWriteMemory8:
case Opcode::ExclusiveWriteMemory16:
case Opcode::ExclusiveWriteMemory32:
case Opcode::ExclusiveWriteMemory64:
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) {
case Opcode::GetCpsr:
case Opcode::GetNFlag:
case Opcode::GetZFlag:
case Opcode::GetCFlag:
case Opcode::GetVFlag:
return true;
default:
return false;
}
}
bool Inst::WritesToCPSR() const {
switch (op) {
case Opcode::SetCpsr:
case Opcode::SetNFlag:
case Opcode::SetZFlag:
case Opcode::SetCFlag:
case Opcode::SetVFlag:
case Opcode::OrQFlag:
return true;
default:
return false;
}
}
bool Inst::ReadsFromCoreRegister() const {
switch (op) {
case Opcode::GetRegister:
case Opcode::GetExtendedRegister32:
case Opcode::GetExtendedRegister64:
return true;
default:
return false;
}
}
bool Inst::WritesToCoreRegister() const {
switch (op) {
case Opcode::SetRegister:
case Opcode::SetExtendedRegister32:
case Opcode::SetExtendedRegister64:
case Opcode::BXWritePC:
return true;
default:
return false;
}
}
bool Inst::ReadsFromFPSCR() const {
switch (op) {
case Opcode::FPAbs32:
case Opcode::FPAbs64:
case Opcode::FPAdd32:
case Opcode::FPAdd64:
case Opcode::FPDiv32:
case Opcode::FPDiv64:
case Opcode::FPMul32:
case Opcode::FPMul64:
case Opcode::FPNeg32:
case Opcode::FPNeg64:
case Opcode::FPSqrt32:
case Opcode::FPSqrt64:
case Opcode::FPSub32:
case Opcode::FPSub64:
return true;
default:
return false;
}
}
bool Inst::WritesToFPSCR() const {
switch (op) {
case Opcode::FPAbs32:
case Opcode::FPAbs64:
case Opcode::FPAdd32:
case Opcode::FPAdd64:
case Opcode::FPDiv32:
case Opcode::FPDiv64:
case Opcode::FPMul32:
case Opcode::FPMul64:
case Opcode::FPNeg32:
case Opcode::FPNeg64:
case Opcode::FPSqrt32:
case Opcode::FPSqrt64:
case Opcode::FPSub32:
case Opcode::FPSub64:
return true;
default:
return false;
}
}
bool Inst::CausesCPUException() const {
return op == Opcode::Breakpoint ||
op == Opcode::CallSupervisor;
}
bool Inst::AltersExclusiveState() const {
return op == Opcode::ClearExclusive ||
op == Opcode::SetExclusive ||
IsExclusiveMemoryWrite();
}
bool Inst::MayHaveSideEffects() const {
return op == Opcode::PushRSB ||
CausesCPUException() ||
WritesToCoreRegister() ||
WritesToCPSR() ||
WritesToFPSCR() ||
AltersExclusiveState() ||
IsMemoryWrite();
}
Type Inst::GetType() const {
if (op == Opcode::Identity)
return args[0].GetType();
return GetTypeOf(op);
}
Value Inst::GetArg(size_t index) const {
DEBUG_ASSERT(index < GetNumArgsOf(op));
DEBUG_ASSERT(!args[index].IsEmpty());
return args[index];
}
void Inst::SetArg(size_t index, Value value) {
DEBUG_ASSERT(index < GetNumArgsOf(op));
DEBUG_ASSERT(AreTypesCompatible(value.GetType(), GetArgTypeOf(op, index)));
if (!args[index].IsImmediate()) {
UndoUse(args[index]);
}
if (!value.IsImmediate()) {
Use(value);
}
args[index] = value;
}
void Inst::Invalidate() {
for (auto& value : args) {
if (!value.IsImmediate()) {
UndoUse(value);
}
}
}
void Inst::ReplaceUsesWith(Value& replacement) {
Invalidate();
op = Opcode::Identity;
if (!replacement.IsImmediate()) {
Use(replacement);
}
args[0] = replacement;
}
void Inst::Use(Value& value) {
value.GetInst()->use_count++;
switch (op){
case Opcode::GetCarryFromOp:
value.GetInst()->carry_inst = this;
break;
case Opcode::GetOverflowFromOp:
value.GetInst()->overflow_inst = this;
break;
default:
break;
}
}
void Inst::UndoUse(Value& value) {
value.GetInst()->use_count--;
switch (op){
case Opcode::GetCarryFromOp:
value.GetInst()->carry_inst = nullptr;
break;
case Opcode::GetOverflowFromOp:
value.GetInst()->overflow_inst = nullptr;
break;
default:
break;
}
}
} // namespace IR
} // namespace Dynarmic