early-access version 1255

This commit is contained in:
pineappleEA
2020-12-28 15:15:37 +00:00
parent 84b39492d1
commit 78b48028e1
6254 changed files with 1868140 additions and 0 deletions

View File

@@ -0,0 +1,245 @@
/* This file is part of the dynarmic project.
* Copyright (c) 2016 MerryMage
* SPDX-License-Identifier: 0BSD
*/
#include <algorithm>
#include <initializer_list>
#include <map>
#include <string>
#include <fmt/format.h>
#include <fmt/ostream.h>
#include "common/assert.h"
#include "common/memory_pool.h"
#include "frontend/A32/types.h"
#include "frontend/A64/types.h"
#include "frontend/ir/basic_block.h"
#include "frontend/ir/cond.h"
#include "frontend/ir/opcodes.h"
namespace Dynarmic::IR {
Block::Block(const LocationDescriptor& location)
: location{location}, end_location{location}, cond{Cond::AL},
instruction_alloc_pool{std::make_unique<Common::Pool>(sizeof(Inst), 4096)} {}
Block::~Block() = default;
Block::Block(Block&&) = default;
Block& Block::operator=(Block&&) = default;
void Block::AppendNewInst(Opcode opcode, std::initializer_list<IR::Value> args) {
PrependNewInst(end(), opcode, args);
}
Block::iterator Block::PrependNewInst(iterator insertion_point, Opcode opcode, std::initializer_list<Value> args) {
IR::Inst* inst = new(instruction_alloc_pool->Alloc()) IR::Inst(opcode);
ASSERT(args.size() == inst->NumArgs());
std::for_each(args.begin(), args.end(), [&inst, index = size_t(0)](const auto& arg) mutable {
inst->SetArg(index, arg);
index++;
});
return instructions.insert_before(insertion_point, inst);
}
LocationDescriptor Block::Location() const {
return location;
}
LocationDescriptor Block::EndLocation() const {
return end_location;
}
void Block::SetEndLocation(const LocationDescriptor& descriptor) {
end_location = descriptor;
}
Cond Block::GetCondition() const {
return cond;
}
void Block::SetCondition(Cond condition) {
cond = condition;
}
LocationDescriptor Block::ConditionFailedLocation() const {
return *cond_failed;
}
void Block::SetConditionFailedLocation(LocationDescriptor fail_location) {
cond_failed = fail_location;
}
size_t& Block::ConditionFailedCycleCount() {
return cond_failed_cycle_count;
}
const size_t& Block::ConditionFailedCycleCount() const {
return cond_failed_cycle_count;
}
bool Block::HasConditionFailedLocation() const {
return cond_failed.has_value();
}
Block::InstructionList& Block::Instructions() {
return instructions;
}
const Block::InstructionList& Block::Instructions() const {
return instructions;
}
Terminal Block::GetTerminal() const {
return terminal;
}
void Block::SetTerminal(Terminal term) {
ASSERT_MSG(!HasTerminal(), "Terminal has already been set.");
terminal = std::move(term);
}
void Block::ReplaceTerminal(Terminal term) {
ASSERT_MSG(HasTerminal(), "Terminal has not been set.");
terminal = std::move(term);
}
bool Block::HasTerminal() const {
return terminal.which() != 0;
}
size_t& Block::CycleCount() {
return cycle_count;
}
const size_t& Block::CycleCount() const {
return cycle_count;
}
static std::string TerminalToString(const Terminal& terminal_variant) {
struct : boost::static_visitor<std::string> {
std::string operator()(const Term::Invalid&) const {
return "<invalid terminal>";
}
std::string operator()(const Term::Interpret& terminal) const {
return fmt::format("Interpret{{{}}}", terminal.next);
}
std::string operator()(const Term::ReturnToDispatch&) const {
return "ReturnToDispatch{}";
}
std::string operator()(const Term::LinkBlock& terminal) const {
return fmt::format("LinkBlock{{{}}}", terminal.next);
}
std::string operator()(const Term::LinkBlockFast& terminal) const {
return fmt::format("LinkBlockFast{{{}}}", terminal.next);
}
std::string operator()(const Term::PopRSBHint&) const {
return "PopRSBHint{}";
}
std::string operator()(const Term::FastDispatchHint&) const {
return "FastDispatchHint{}";
}
std::string operator()(const Term::If& terminal) const {
return fmt::format("If{{{}, {}, {}}}", A64::CondToString(terminal.if_), TerminalToString(terminal.then_), TerminalToString(terminal.else_));
}
std::string operator()(const Term::CheckBit& terminal) const {
return fmt::format("CheckBit{{{}, {}}}", TerminalToString(terminal.then_), TerminalToString(terminal.else_));
}
std::string operator()(const Term::CheckHalt& terminal) const {
return fmt::format("CheckHalt{{{}}}", TerminalToString(terminal.else_));
}
} visitor;
return boost::apply_visitor(visitor, terminal_variant);
}
std::string DumpBlock(const IR::Block& block) {
std::string ret;
ret += fmt::format("Block: location={}\n", block.Location());
ret += fmt::format("cycles={}", block.CycleCount());
ret += fmt::format(", entry_cond={}", A64::CondToString(block.GetCondition()));
if (block.GetCondition() != Cond::AL) {
ret += fmt::format(", cond_fail={}", block.ConditionFailedLocation());
}
ret += '\n';
std::map<const IR::Inst*, size_t> inst_to_index;
size_t index = 0;
const auto arg_to_string = [&inst_to_index](const IR::Value& arg) -> std::string {
if (arg.IsEmpty()) {
return "<null>";
} else if (!arg.IsImmediate()) {
if (const auto iter = inst_to_index.find(arg.GetInst()); iter != inst_to_index.end()) {
return fmt::format("%{}", iter->second);
}
return fmt::format("%<unknown inst {:016x}>", reinterpret_cast<u64>(arg.GetInst()));
}
switch (arg.GetType()) {
case Type::U1:
return fmt::format("#{}", arg.GetU1() ? '1' : '0');
case Type::U8:
return fmt::format("#{}", arg.GetU8());
case Type::U16:
return fmt::format("#{:#x}", arg.GetU16());
case Type::U32:
return fmt::format("#{:#x}", arg.GetU32());
case Type::U64:
return fmt::format("#{:#x}", arg.GetU64());
case Type::A32Reg:
return A32::RegToString(arg.GetA32RegRef());
case Type::A32ExtReg:
return A32::ExtRegToString(arg.GetA32ExtRegRef());
case Type::A64Reg:
return A64::RegToString(arg.GetA64RegRef());
case Type::A64Vec:
return A64::VecToString(arg.GetA64VecRef());
default:
return "<unknown immediate type>";
}
};
for (const auto& inst : block) {
const Opcode op = inst.GetOpcode();
ret += fmt::format("[{:016x}] ", reinterpret_cast<u64>(&inst));
if (GetTypeOf(op) != Type::Void) {
ret += fmt::format("%{:<5} = ", index);
} else {
ret += " "; // '%00000 = ' -> 1 + 5 + 3 = 9 spaces
}
ret += GetNameOf(op);
const size_t arg_count = GetNumArgsOf(op);
for (size_t arg_index = 0; arg_index < arg_count; arg_index++) {
const Value arg = inst.GetArg(arg_index);
ret += arg_index != 0 ? ", " : " ";
ret += arg_to_string(arg);
Type actual_type = arg.GetType();
Type expected_type = GetArgTypeOf(op, arg_index);
if (!AreTypesCompatible(actual_type, expected_type)) {
ret += fmt::format("<type error: {} != {}>", GetNameOf(actual_type), GetNameOf(expected_type));
}
}
ret += fmt::format(" (uses: {})", inst.UseCount());
ret += '\n';
inst_to_index[&inst] = index++;
}
ret += "terminal = " + TerminalToString(block.GetTerminal()) + '\n';
return ret;
}
} // namespace Dynarmic::IR

View File

@@ -0,0 +1,167 @@
/* This file is part of the dynarmic project.
* Copyright (c) 2016 MerryMage
* SPDX-License-Identifier: 0BSD
*/
#pragma once
#include <initializer_list>
#include <memory>
#include <optional>
#include <string>
#include "common/common_types.h"
#include "common/intrusive_list.h"
#include "frontend/ir/location_descriptor.h"
#include "frontend/ir/microinstruction.h"
#include "frontend/ir/terminal.h"
#include "frontend/ir/value.h"
namespace Dynarmic::Common {
class Pool;
}
namespace Dynarmic::IR {
enum class Cond;
enum class Opcode;
/**
* A basic block. It consists of zero or more instructions followed by exactly one terminal.
* Note that this is a linear IR and not a pure tree-based IR: i.e.: there is an ordering to
* the microinstructions. This only matters before chaining is done in order to correctly
* order memory accesses.
*/
class Block final {
public:
using InstructionList = Common::IntrusiveList<Inst>;
using size_type = InstructionList::size_type;
using iterator = InstructionList::iterator;
using const_iterator = InstructionList::const_iterator;
using reverse_iterator = InstructionList::reverse_iterator;
using const_reverse_iterator = InstructionList::const_reverse_iterator;
explicit Block(const LocationDescriptor& location);
~Block();
Block(const Block&) = delete;
Block& operator=(const Block&) = delete;
Block(Block&&);
Block& operator=(Block&&);
bool empty() const { return instructions.empty(); }
size_type size() const { return instructions.size(); }
Inst& front() { return instructions.front(); }
const Inst& front() const { return instructions.front(); }
Inst& back() { return instructions.back(); }
const Inst& back() const { return instructions.back(); }
iterator begin() { return instructions.begin(); }
const_iterator begin() const { return instructions.begin(); }
iterator end() { return instructions.end(); }
const_iterator end() const { return instructions.end(); }
reverse_iterator rbegin() { return instructions.rbegin(); }
const_reverse_iterator rbegin() const { return instructions.rbegin(); }
reverse_iterator rend() { return instructions.rend(); }
const_reverse_iterator rend() const { return instructions.rend(); }
const_iterator cbegin() const { return instructions.cbegin(); }
const_iterator cend() const { return instructions.cend(); }
const_reverse_iterator crbegin() const { return instructions.crbegin(); }
const_reverse_iterator crend() const { return instructions.crend(); }
/**
* Appends a new instruction to the end of this basic block,
* handling any allocations necessary to do so.
*
* @param op Opcode representing the instruction to add.
* @param args A sequence of Value instances used as arguments for the instruction.
*/
void AppendNewInst(Opcode op, std::initializer_list<Value> args);
/**
* Prepends a new instruction to this basic block before the insertion point,
* handling any allocations necessary to do so.
*
* @param insertion_point Where to insert the new instruction.
* @param op Opcode representing the instruction to add.
* @param args A sequence of Value instances used as arguments for the instruction.
* @returns Iterator to the newly created instruction.
*/
iterator PrependNewInst(iterator insertion_point, Opcode op, std::initializer_list<Value> args);
/// Gets the starting location for this basic block.
LocationDescriptor Location() const;
/// Gets the end location for this basic block.
LocationDescriptor EndLocation() const;
/// Sets the end location for this basic block.
void SetEndLocation(const LocationDescriptor& descriptor);
/// Gets the condition required to pass in order to execute this block.
Cond GetCondition() const;
/// Sets the condition required to pass in order to execute this block.
void SetCondition(Cond condition);
/// Gets the location of the block to execute if the predicated condition fails.
LocationDescriptor ConditionFailedLocation() const;
/// Sets the location of the block to execute if the predicated condition fails.
void SetConditionFailedLocation(LocationDescriptor fail_location);
/// Determines whether or not a predicated condition failure block is present.
bool HasConditionFailedLocation() const;
/// Gets a mutable reference to the condition failed cycle count.
size_t& ConditionFailedCycleCount();
/// Gets an immutable reference to the condition failed cycle count.
const size_t& ConditionFailedCycleCount() const;
/// Gets a mutable reference to the instruction list for this basic block.
InstructionList& Instructions();
/// Gets an immutable reference to the instruction list for this basic block.
const InstructionList& Instructions() const;
/// Gets the terminal instruction for this basic block.
Terminal GetTerminal() const;
/// Sets the terminal instruction for this basic block.
void SetTerminal(Terminal term);
/// Replaces the terminal instruction for this basic block.
void ReplaceTerminal(Terminal term);
/// Determines whether or not this basic block has a terminal instruction.
bool HasTerminal() const;
/// Gets a mutable reference to the cycle count for this basic block.
size_t& CycleCount();
/// Gets an immutable reference to the cycle count for this basic block.
const size_t& CycleCount() const;
private:
/// Description of the starting location of this block
LocationDescriptor location;
/// Description of the end location of this block
LocationDescriptor end_location;
/// Conditional to pass in order to execute this block
Cond cond;
/// Block to execute next if `cond` did not pass.
std::optional<LocationDescriptor> cond_failed = {};
/// Number of cycles this block takes to execute if the conditional fails.
size_t cond_failed_cycle_count = 0;
/// List of instructions in this block.
InstructionList instructions;
/// Memory pool for instruction list
std::unique_ptr<Common::Pool> instruction_alloc_pool;
/// Terminal instruction of this block.
Terminal terminal = Term::Invalid{};
/// Number of cycles this block takes to execute.
size_t cycle_count = 0;
};
/// Returns a string representation of the contents of block. Intended for debugging.
std::string DumpBlock(const IR::Block& block);
} // namespace Dynarmic::IR

15
externals/dynarmic/src/frontend/ir/cond.h vendored Executable file
View File

@@ -0,0 +1,15 @@
/* This file is part of the dynarmic project.
* Copyright (c) 2016 MerryMage
* SPDX-License-Identifier: 0BSD
*/
#pragma once
namespace Dynarmic::IR {
enum class Cond {
EQ, NE, CS, CC, MI, PL, VS, VC, HI, LS, GE, LT, GT, LE, AL, NV,
HS = CS, LO = CC,
};
} // namespace Dynarmic::IR

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,402 @@
/* This file is part of the dynarmic project.
* Copyright (c) 2016 MerryMage
* SPDX-License-Identifier: 0BSD
*/
#pragma once
#include "common/common_types.h"
#include "frontend/ir/basic_block.h"
#include "frontend/ir/location_descriptor.h"
#include "frontend/ir/terminal.h"
#include "frontend/ir/value.h"
namespace Dynarmic::FP {
enum class RoundingMode;
} // namespace Dynarmic::FP
// ARM JIT Microinstruction Intermediate Representation
//
// This intermediate representation is an SSA IR. It is designed primarily for analysis,
// though it can be lowered into a reduced form for interpretation. Each IR node (Value)
// is a microinstruction of an idealised ARM CPU. The choice of microinstructions is made
// not based on any existing microarchitecture but on ease of implementation.
namespace Dynarmic::IR {
enum class Opcode;
template <typename T>
struct ResultAndCarry {
T result;
U1 carry;
};
template <typename T>
struct ResultAndOverflow {
T result;
U1 overflow;
};
template <typename T>
struct ResultAndCarryAndOverflow {
T result;
U1 carry;
U1 overflow;
};
template <typename T>
struct ResultAndGE {
T result;
U32 ge;
};
struct UpperAndLower {
U128 upper;
U128 lower;
};
enum class AccType {
NORMAL, VEC, STREAM, VECSTREAM,
ATOMIC, ORDERED, ORDEREDRW, LIMITEDORDERED,
UNPRIV, IFETCH, PTW, DC, IC, DCZVA, AT,
};
enum class MemOp {
LOAD, STORE, PREFETCH,
};
/**
* Convenience class to construct a basic block of the intermediate representation.
* `block` is the resulting block.
* The user of this class updates `current_location` as appropriate.
*/
class IREmitter {
public:
explicit IREmitter(Block& block) : block(block), insertion_point(block.end()) {}
Block& block;
U1 Imm1(bool value) const;
U8 Imm8(u8 value) const;
U16 Imm16(u16 value) const;
U32 Imm32(u32 value) const;
U64 Imm64(u64 value) const;
void PushRSB(const LocationDescriptor& return_location);
U64 Pack2x32To1x64(const U32& lo, const U32& hi);
U128 Pack2x64To1x128(const U64& lo, const U64& hi);
UAny LeastSignificant(size_t bitsize, const U32U64& value);
U32 LeastSignificantWord(const U64& value);
U16 LeastSignificantHalf(U32U64 value);
U8 LeastSignificantByte(U32U64 value);
ResultAndCarry<U32> MostSignificantWord(const U64& value);
U1 MostSignificantBit(const U32& value);
U1 IsZero(const U32& value);
U1 IsZero(const U64& value);
U1 IsZero(const U32U64& value);
U1 TestBit(const U32U64& value, const U8& bit);
U32 ConditionalSelect(Cond cond, const U32& a, const U32& b);
U64 ConditionalSelect(Cond cond, const U64& a, const U64& b);
NZCV ConditionalSelect(Cond cond, const NZCV& a, const NZCV& b);
U32U64 ConditionalSelect(Cond cond, const U32U64& a, const U32U64& b);
NZCV NZCVFromPackedFlags(const U32& a);
// This pseudo-instruction may only be added to instructions that support it.
NZCV NZCVFrom(const Value& value);
ResultAndCarry<U32> LogicalShiftLeft(const U32& value_in, const U8& shift_amount, const U1& carry_in);
ResultAndCarry<U32> LogicalShiftRight(const U32& value_in, const U8& shift_amount, const U1& carry_in);
ResultAndCarry<U32> ArithmeticShiftRight(const U32& value_in, const U8& shift_amount, const U1& carry_in);
ResultAndCarry<U32> RotateRight(const U32& value_in, const U8& shift_amount, const U1& carry_in);
U32U64 LogicalShiftLeft(const U32U64& value_in, const U8& shift_amount);
U32U64 LogicalShiftRight(const U32U64& value_in, const U8& shift_amount);
U32U64 ArithmeticShiftRight(const U32U64& value_in, const U8& shift_amount);
U32U64 RotateRight(const U32U64& value_in, const U8& shift_amount);
U32U64 LogicalShiftLeftMasked(const U32U64& value_in, const U32U64& shift_amount);
U32U64 LogicalShiftRightMasked(const U32U64& value_in, const U32U64& shift_amount);
U32U64 ArithmeticShiftRightMasked(const U32U64& value_in, const U32U64& shift_amount);
U32U64 RotateRightMasked(const U32U64& value_in, const U32U64& shift_amount);
ResultAndCarry<U32> RotateRightExtended(const U32& value_in, const U1& carry_in);
ResultAndCarryAndOverflow<U32> AddWithCarry(const U32& a, const U32& b, const U1& carry_in);
ResultAndCarryAndOverflow<U32> SubWithCarry(const U32& a, const U32& b, const U1& carry_in);
U32U64 AddWithCarry(const U32U64& a, const U32U64& b, const U1& carry_in);
U32U64 SubWithCarry(const U32U64& a, const U32U64& b, const U1& carry_in);
U32U64 Add(const U32U64& a, const U32U64& b);
U32U64 Sub(const U32U64& a, const U32U64& b);
U32U64 Mul(const U32U64& a, const U32U64& b);
U64 UnsignedMultiplyHigh(const U64& a, const U64& b);
U64 SignedMultiplyHigh(const U64& a, const U64& b);
U32U64 UnsignedDiv(const U32U64& a, const U32U64& b);
U32U64 SignedDiv(const U32U64& a, const U32U64& b);
U32U64 And(const U32U64& a, const U32U64& b);
U32U64 Eor(const U32U64& a, const U32U64& b);
U32U64 Or(const U32U64& a, const U32U64& b);
U32U64 Not(const U32U64& a);
U32 SignExtendToWord(const UAny& a);
U64 SignExtendToLong(const UAny& a);
U32 SignExtendByteToWord(const U8& a);
U32 SignExtendHalfToWord(const U16& a);
U64 SignExtendWordToLong(const U32& a);
U32 ZeroExtendToWord(const UAny& a);
U64 ZeroExtendToLong(const UAny& a);
U128 ZeroExtendToQuad(const UAny& a);
U32 ZeroExtendByteToWord(const U8& a);
U32 ZeroExtendHalfToWord(const U16& a);
U64 ZeroExtendWordToLong(const U32& a);
U32 IndeterminateExtendToWord(const UAny& a);
U64 IndeterminateExtendToLong(const UAny& a);
U32 ByteReverseWord(const U32& a);
U16 ByteReverseHalf(const U16& a);
U64 ByteReverseDual(const U64& a);
U32U64 CountLeadingZeros(const U32U64& a);
U32U64 ExtractRegister(const U32U64& a, const U32U64& b, const U8& lsb);
U32U64 ReplicateBit(const U32U64& a, u8 bit);
U32U64 MaxSigned(const U32U64& a, const U32U64& b);
U32U64 MaxUnsigned(const U32U64& a, const U32U64& b);
U32U64 MinSigned(const U32U64& a, const U32U64& b);
U32U64 MinUnsigned(const U32U64& a, const U32U64& b);
ResultAndOverflow<UAny> SignedSaturatedAdd(const UAny& a, const UAny& b);
ResultAndOverflow<UAny> SignedSaturatedDoublingMultiplyReturnHigh(const UAny& a, const UAny& b);
ResultAndOverflow<UAny> SignedSaturatedSub(const UAny& a, const UAny& b);
ResultAndOverflow<U32> SignedSaturation(const U32& a, size_t bit_size_to_saturate_to);
ResultAndOverflow<UAny> UnsignedSaturatedAdd(const UAny& a, const UAny& b);
ResultAndOverflow<UAny> UnsignedSaturatedSub(const UAny& a, const UAny& b);
ResultAndOverflow<U32> UnsignedSaturation(const U32& a, size_t bit_size_to_saturate_to);
U128 VectorSignedSaturatedAdd(size_t esize, const U128& a, const U128& b);
U128 VectorSignedSaturatedSub(size_t esize, const U128& a, const U128& b);
U128 VectorUnsignedSaturatedAdd(size_t esize, const U128& a, const U128& b);
U128 VectorUnsignedSaturatedSub(size_t esize, const U128& a, const U128& b);
ResultAndGE<U32> PackedAddU8(const U32& a, const U32& b);
ResultAndGE<U32> PackedAddS8(const U32& a, const U32& b);
ResultAndGE<U32> PackedAddU16(const U32& a, const U32& b);
ResultAndGE<U32> PackedAddS16(const U32& a, const U32& b);
ResultAndGE<U32> PackedSubU8(const U32& a, const U32& b);
ResultAndGE<U32> PackedSubS8(const U32& a, const U32& b);
ResultAndGE<U32> PackedSubU16(const U32& a, const U32& b);
ResultAndGE<U32> PackedSubS16(const U32& a, const U32& b);
ResultAndGE<U32> PackedAddSubU16(const U32& a, const U32& b);
ResultAndGE<U32> PackedAddSubS16(const U32& a, const U32& b);
ResultAndGE<U32> PackedSubAddU16(const U32& a, const U32& b);
ResultAndGE<U32> PackedSubAddS16(const U32& a, const U32& b);
U32 PackedHalvingAddU8(const U32& a, const U32& b);
U32 PackedHalvingAddS8(const U32& a, const U32& b);
U32 PackedHalvingSubU8(const U32& a, const U32& b);
U32 PackedHalvingSubS8(const U32& a, const U32& b);
U32 PackedHalvingAddU16(const U32& a, const U32& b);
U32 PackedHalvingAddS16(const U32& a, const U32& b);
U32 PackedHalvingSubU16(const U32& a, const U32& b);
U32 PackedHalvingSubS16(const U32& a, const U32& b);
U32 PackedHalvingAddSubU16(const U32& a, const U32& b);
U32 PackedHalvingAddSubS16(const U32& a, const U32& b);
U32 PackedHalvingSubAddU16(const U32& a, const U32& b);
U32 PackedHalvingSubAddS16(const U32& a, const U32& b);
U32 PackedSaturatedAddU8(const U32& a, const U32& b);
U32 PackedSaturatedAddS8(const U32& a, const U32& b);
U32 PackedSaturatedSubU8(const U32& a, const U32& b);
U32 PackedSaturatedSubS8(const U32& a, const U32& b);
U32 PackedSaturatedAddU16(const U32& a, const U32& b);
U32 PackedSaturatedAddS16(const U32& a, const U32& b);
U32 PackedSaturatedSubU16(const U32& a, const U32& b);
U32 PackedSaturatedSubS16(const U32& a, const U32& b);
U32 PackedAbsDiffSumS8(const U32& a, const U32& b);
U32 PackedSelect(const U32& ge, const U32& a, const U32& b);
U32 CRC32Castagnoli8(const U32& a, const U32& b);
U32 CRC32Castagnoli16(const U32& a, const U32& b);
U32 CRC32Castagnoli32(const U32& a, const U32& b);
U32 CRC32Castagnoli64(const U32& a, const U64& b);
U32 CRC32ISO8(const U32& a, const U32& b);
U32 CRC32ISO16(const U32& a, const U32& b);
U32 CRC32ISO32(const U32& a, const U32& b);
U32 CRC32ISO64(const U32& a, const U64& b);
U128 AESDecryptSingleRound(const U128& a);
U128 AESEncryptSingleRound(const U128& a);
U128 AESInverseMixColumns(const U128& a);
U128 AESMixColumns(const U128& a);
U8 SM4AccessSubstitutionBox(const U8& a);
UAny VectorGetElement(size_t esize, const U128& a, size_t index);
U128 VectorSetElement(size_t esize, const U128& a, size_t index, const UAny& elem);
U128 VectorAbs(size_t esize, const U128& a);
U128 VectorAdd(size_t esize, const U128& a, const U128& b);
U128 VectorAnd(const U128& a, const U128& b);
U128 VectorArithmeticShiftRight(size_t esize, const U128& a, u8 shift_amount);
U128 VectorArithmeticVShift(size_t esize, const U128& a, const U128& b);
U128 VectorBroadcast(size_t esize, const UAny& a);
U128 VectorBroadcastLower(size_t esize, const UAny& a);
U128 VectorCountLeadingZeros(size_t esize, const U128& a);
U128 VectorEor(const U128& a, const U128& b);
U128 VectorDeinterleaveEven(size_t esize, const U128& a, const U128& b);
U128 VectorDeinterleaveEvenLower(size_t esize, const U128& a, const U128& b);
U128 VectorDeinterleaveOdd(size_t esize, const U128& a, const U128& b);
U128 VectorDeinterleaveOddLower(size_t esize, const U128& a, const U128& b);
U128 VectorEqual(size_t esize, const U128& a, const U128& b);
U128 VectorExtract(const U128& a, const U128& b, size_t position);
U128 VectorExtractLower(const U128& a, const U128& b, size_t position);
U128 VectorGreaterEqualSigned(size_t esize, const U128& a, const U128& b);
U128 VectorGreaterEqualUnsigned(size_t esize, const U128& a, const U128& b);
U128 VectorGreaterSigned(size_t esize, const U128& a, const U128& b);
U128 VectorGreaterUnsigned(size_t esize, const U128& a, const U128& b);
U128 VectorHalvingAddSigned(size_t esize, const U128& a, const U128& b);
U128 VectorHalvingAddUnsigned(size_t esize, const U128& a, const U128& b);
U128 VectorHalvingSubSigned(size_t esize, const U128& a, const U128& b);
U128 VectorHalvingSubUnsigned(size_t esize, const U128& a, const U128& b);
U128 VectorInterleaveLower(size_t esize, const U128& a, const U128& b);
U128 VectorInterleaveUpper(size_t esize, const U128& a, const U128& b);
U128 VectorLessEqualSigned(size_t esize, const U128& a, const U128& b);
U128 VectorLessEqualUnsigned(size_t esize, const U128& a, const U128& b);
U128 VectorLessSigned(size_t esize, const U128& a, const U128& b);
U128 VectorLessUnsigned(size_t esize, const U128& a, const U128& b);
U128 VectorLogicalShiftLeft(size_t esize, const U128& a, u8 shift_amount);
U128 VectorLogicalShiftRight(size_t esize, const U128& a, u8 shift_amount);
U128 VectorLogicalVShift(size_t esize, const U128& a, const U128& b);
U128 VectorMaxSigned(size_t esize, const U128& a, const U128& b);
U128 VectorMaxUnsigned(size_t esize, const U128& a, const U128& b);
U128 VectorMinSigned(size_t esize, const U128& a, const U128& b);
U128 VectorMinUnsigned(size_t esize, const U128& a, const U128& b);
U128 VectorMultiply(size_t esize, const U128& a, const U128& b);
U128 VectorNarrow(size_t original_esize, const U128& a);
U128 VectorNot(const U128& a);
U128 VectorOr(const U128& a, const U128& b);
U128 VectorPairedAdd(size_t esize, const U128& a, const U128& b);
U128 VectorPairedAddLower(size_t esize, const U128& a, const U128& b);
U128 VectorPairedAddSignedWiden(size_t original_esize, const U128& a);
U128 VectorPairedAddUnsignedWiden(size_t original_esize, const U128& a);
U128 VectorPairedMaxSigned(size_t esize, const U128& a, const U128& b);
U128 VectorPairedMaxUnsigned(size_t esize, const U128& a, const U128& b);
U128 VectorPairedMinSigned(size_t esize, const U128& a, const U128& b);
U128 VectorPairedMinUnsigned(size_t esize, const U128& a, const U128& b);
U128 VectorPolynomialMultiply(const U128& a, const U128& b);
U128 VectorPolynomialMultiplyLong(size_t esize, const U128& a, const U128& b);
U128 VectorPopulationCount(const U128& a);
U128 VectorReverseBits(const U128& a);
U128 VectorRotateLeft(size_t esize, const U128& a, u8 amount);
U128 VectorRotateRight(size_t esize, const U128& a, u8 amount);
U128 VectorRoundingHalvingAddSigned(size_t esize, const U128& a, const U128& b);
U128 VectorRoundingHalvingAddUnsigned(size_t esize, const U128& a, const U128& b);
U128 VectorRoundingShiftLeftSigned(size_t esize, const U128& a, const U128& b);
U128 VectorRoundingShiftLeftUnsigned(size_t esize, const U128& a, const U128& b);
U128 VectorShuffleHighHalfwords(const U128& a, u8 mask);
U128 VectorShuffleLowHalfwords(const U128& a, u8 mask);
U128 VectorShuffleWords(const U128& a, u8 mask);
U128 VectorSignExtend(size_t original_esize, const U128& a);
U128 VectorSignedAbsoluteDifference(size_t esize, const U128& a, const U128& b);
UpperAndLower VectorSignedMultiply(size_t esize, const U128& a, const U128& b);
U128 VectorSignedSaturatedAbs(size_t esize, const U128& a);
U128 VectorSignedSaturatedAccumulateUnsigned(size_t esize, const U128& a, const U128& b);
UpperAndLower VectorSignedSaturatedDoublingMultiply(size_t esize, const U128& a, const U128& b);
U128 VectorSignedSaturatedDoublingMultiplyLong(size_t esize, const U128& a, const U128& b);
U128 VectorSignedSaturatedNarrowToSigned(size_t original_esize, const U128& a);
U128 VectorSignedSaturatedNarrowToUnsigned(size_t original_esize, const U128& a);
U128 VectorSignedSaturatedNeg(size_t esize, const U128& a);
U128 VectorSignedSaturatedShiftLeft(size_t esize, const U128& a, const U128& b);
U128 VectorSignedSaturatedShiftLeftUnsigned(size_t esize, const U128& a, const U128& b);
U128 VectorSub(size_t esize, const U128& a, const U128& b);
Table VectorTable(std::vector<U64> values);
Table VectorTable(std::vector<U128> values);
U64 VectorTableLookup(const U64& defaults, const Table& table, const U64& indices);
U128 VectorTableLookup(const U128& defaults, const Table& table, const U128& indices);
U128 VectorTranspose(size_t esize, const U128& a, const U128& b, bool part);
U128 VectorUnsignedAbsoluteDifference(size_t esize, const U128& a, const U128& b);
U128 VectorUnsignedRecipEstimate(const U128& a);
U128 VectorUnsignedRecipSqrtEstimate(const U128& a);
U128 VectorUnsignedSaturatedAccumulateSigned(size_t esize, const U128& a, const U128& b);
U128 VectorUnsignedSaturatedNarrow(size_t esize, const U128& a);
U128 VectorUnsignedSaturatedShiftLeft(size_t esize, const U128& a, const U128& b);
U128 VectorZeroExtend(size_t original_esize, const U128& a);
U128 VectorZeroUpper(const U128& a);
U128 ZeroVector();
U16U32U64 FPAbs(const U16U32U64& a);
U32U64 FPAdd(const U32U64& a, const U32U64& b);
NZCV FPCompare(const U32U64& a, const U32U64& b, bool exc_on_qnan);
U32U64 FPDiv(const U32U64& a, const U32U64& b);
U32U64 FPMax(const U32U64& a, const U32U64& b);
U32U64 FPMaxNumeric(const U32U64& a, const U32U64& b);
U32U64 FPMin(const U32U64& a, const U32U64& b);
U32U64 FPMinNumeric(const U32U64& a, const U32U64& b);
U32U64 FPMul(const U32U64& a, const U32U64& b);
U16U32U64 FPMulAdd(const U16U32U64& addend, const U16U32U64& op1, const U16U32U64& op2);
U32U64 FPMulX(const U32U64& a, const U32U64& b);
U16U32U64 FPNeg(const U16U32U64& a);
U16U32U64 FPRecipEstimate(const U16U32U64& a);
U16U32U64 FPRecipExponent(const U16U32U64& a);
U16U32U64 FPRecipStepFused(const U16U32U64& a, const U16U32U64& b);
U16U32U64 FPRoundInt(const U16U32U64& a, FP::RoundingMode rounding, bool exact);
U16U32U64 FPRSqrtEstimate(const U16U32U64& a);
U16U32U64 FPRSqrtStepFused(const U16U32U64& a, const U16U32U64& b);
U32U64 FPSqrt(const U32U64& a);
U32U64 FPSub(const U32U64& a, const U32U64& b);
U16 FPDoubleToHalf(const U64& a, FP::RoundingMode rounding);
U32 FPDoubleToSingle(const U64& a, FP::RoundingMode rounding);
U64 FPHalfToDouble(const U16& a, FP::RoundingMode rounding);
U32 FPHalfToSingle(const U16& a, FP::RoundingMode rounding);
U16 FPSingleToHalf(const U32& a, FP::RoundingMode rounding);
U64 FPSingleToDouble(const U32& a, FP::RoundingMode rounding);
U16 FPToFixedS16(const U16U32U64& a, size_t fbits, FP::RoundingMode rounding);
U32 FPToFixedS32(const U16U32U64& a, size_t fbits, FP::RoundingMode rounding);
U64 FPToFixedS64(const U16U32U64& a, size_t fbits, FP::RoundingMode rounding);
U16 FPToFixedU16(const U16U32U64& a, size_t fbits, FP::RoundingMode rounding);
U32 FPToFixedU32(const U16U32U64& a, size_t fbits, FP::RoundingMode rounding);
U64 FPToFixedU64(const U16U32U64& a, size_t fbits, FP::RoundingMode rounding);
U32 FPSignedFixedToSingle(const U16U32U64& a, size_t fbits, FP::RoundingMode rounding);
U32 FPUnsignedFixedToSingle(const U16U32U64& a, size_t fbits, FP::RoundingMode rounding);
U64 FPSignedFixedToDouble(const U16U32U64& a, size_t fbits, FP::RoundingMode rounding);
U64 FPUnsignedFixedToDouble(const U16U32U64& a, size_t fbits, FP::RoundingMode rounding);
U128 FPVectorAbs(size_t esize, const U128& a);
U128 FPVectorAdd(size_t esize, const U128& a, const U128& b, bool fpcr_controlled = true);
U128 FPVectorDiv(size_t esize, const U128& a, const U128& b, bool fpcr_controlled = true);
U128 FPVectorEqual(size_t esize, const U128& a, const U128& b, bool fpcr_controlled = true);
U128 FPVectorFromSignedFixed(size_t esize, const U128& a, size_t fbits, FP::RoundingMode rounding, bool fpcr_controlled = true);
U128 FPVectorFromUnsignedFixed(size_t esize, const U128& a, size_t fbits, FP::RoundingMode rounding, bool fpcr_controlled = true);
U128 FPVectorGreater(size_t esize, const U128& a, const U128& b, bool fpcr_controlled = true);
U128 FPVectorGreaterEqual(size_t esize, const U128& a, const U128& b, bool fpcr_controlled = true);
U128 FPVectorMax(size_t esize, const U128& a, const U128& b, bool fpcr_controlled = true);
U128 FPVectorMin(size_t esize, const U128& a, const U128& b, bool fpcr_controlled = true);
U128 FPVectorMul(size_t esize, const U128& a, const U128& b, bool fpcr_controlled = true);
U128 FPVectorMulAdd(size_t esize, const U128& addend, const U128& op1, const U128& op2, bool fpcr_controlled = true);
U128 FPVectorMulX(size_t esize, const U128& a, const U128& b, bool fpcr_controlled = true);
U128 FPVectorNeg(size_t esize, const U128& a);
U128 FPVectorPairedAdd(size_t esize, const U128& a, const U128& b, bool fpcr_controlled = true);
U128 FPVectorPairedAddLower(size_t esize, const U128& a, const U128& b, bool fpcr_controlled = true);
U128 FPVectorRecipEstimate(size_t esize, const U128& a, bool fpcr_controlled = true);
U128 FPVectorRecipStepFused(size_t esize, const U128& a, const U128& b, bool fpcr_controlled = true);
U128 FPVectorRoundInt(size_t esize, const U128& operand, FP::RoundingMode rounding, bool exact, bool fpcr_controlled = true);
U128 FPVectorRSqrtEstimate(size_t esize, const U128& a, bool fpcr_controlled = true);
U128 FPVectorRSqrtStepFused(size_t esize, const U128& a, const U128& b, bool fpcr_controlled = true);
U128 FPVectorSqrt(size_t esize, const U128& a, bool fpcr_controlled = true);
U128 FPVectorSub(size_t esize, const U128& a, const U128& b, bool fpcr_controlled = true);
U128 FPVectorToSignedFixed(size_t esize, const U128& a, size_t fbits, FP::RoundingMode rounding, bool fpcr_controlled = true);
U128 FPVectorToUnsignedFixed(size_t esize, const U128& a, size_t fbits, FP::RoundingMode rounding, bool fpcr_controlled = true);
void Breakpoint();
void SetTerm(const Terminal& terminal);
void SetInsertionPoint(IR::Inst* new_insertion_point) {
insertion_point = IR::Block::iterator{*new_insertion_point};
}
void SetInsertionPoint(IR::Block::iterator new_insertion_point) {
insertion_point = new_insertion_point;
}
protected:
IR::Block::iterator insertion_point;
template<typename T = Value, typename ...Args>
T Inst(Opcode op, Args ...args) {
auto iter = block.PrependNewInst(insertion_point, op, {Value(args)...});
return T(Value(&*iter));
}
};
} // namespace Dynarmic::IR

View File

@@ -0,0 +1,18 @@
/* This file is part of the dynarmic project.
* Copyright (c) 2016 MerryMage
* SPDX-License-Identifier: 0BSD
*/
#include <ostream>
#include <fmt/format.h>
#include "frontend/ir/location_descriptor.h"
namespace Dynarmic::IR {
std::ostream& operator<<(std::ostream& o, const LocationDescriptor& descriptor) {
o << fmt::format("{{{:016x}}}", descriptor.Value());
return o;
}
} // namespace Dynarmic::IR

View File

@@ -0,0 +1,54 @@
/* This file is part of the dynarmic project.
* Copyright (c) 2016 MerryMage
* SPDX-License-Identifier: 0BSD
*/
#pragma once
#include <functional>
#include <iosfwd>
#include "common/common_types.h"
namespace Dynarmic::IR {
class LocationDescriptor {
public:
explicit LocationDescriptor(u64 value) : value(value) {}
bool operator == (const LocationDescriptor& o) const {
return value == o.Value();
}
bool operator != (const LocationDescriptor& o) const {
return !operator==(o);
}
u64 Value() const { return value; }
private:
u64 value;
};
std::ostream& operator<<(std::ostream& o, const LocationDescriptor& descriptor);
inline bool operator<(const LocationDescriptor& x, const LocationDescriptor& y) noexcept {
return x.Value() < y.Value();
}
} // namespace Dynarmic::IR
namespace std {
template <>
struct less<Dynarmic::IR::LocationDescriptor> {
bool operator()(const Dynarmic::IR::LocationDescriptor& x, const Dynarmic::IR::LocationDescriptor& y) const noexcept {
return x < y;
}
};
template <>
struct hash<Dynarmic::IR::LocationDescriptor> {
size_t operator()(const Dynarmic::IR::LocationDescriptor& x) const noexcept {
return std::hash<u64>()(x.Value());
}
};
} // namespace std

View File

@@ -0,0 +1,732 @@
/* This file is part of the dynarmic project.
* Copyright (c) 2016 MerryMage
* SPDX-License-Identifier: 0BSD
*/
#include <algorithm>
#include <fmt/ostream.h>
#include "common/assert.h"
#include "frontend/ir/microinstruction.h"
#include "frontend/ir/opcodes.h"
#include "frontend/ir/type.h"
namespace Dynarmic::IR {
bool Inst::IsArithmeticShift() const {
return op == Opcode::ArithmeticShiftRight32 ||
op == Opcode::ArithmeticShiftRight64;
}
bool Inst::IsCircularShift() const {
return op == Opcode::RotateRight32 ||
op == Opcode::RotateRight64 ||
op == Opcode::RotateRightExtended;
}
bool Inst::IsLogicalShift() const {
switch (op) {
case Opcode::LogicalShiftLeft32:
case Opcode::LogicalShiftLeft64:
case Opcode::LogicalShiftRight32:
case Opcode::LogicalShiftRight64:
return true;
default:
return false;
}
}
bool Inst::IsShift() const {
return IsArithmeticShift() ||
IsCircularShift() ||
IsLogicalShift();
}
bool Inst::IsBarrier() const {
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;
}
}
bool Inst::IsSharedMemoryRead() const {
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;
}
}
bool Inst::IsSharedMemoryWrite() const {
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;
}
}
bool Inst::IsSharedMemoryReadOrWrite() const {
return IsSharedMemoryRead() || IsSharedMemoryWrite();
}
bool Inst::IsExclusiveMemoryRead() const {
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;
}
}
bool Inst::IsExclusiveMemoryWrite() const {
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;
}
}
bool Inst::IsMemoryRead() const {
return IsSharedMemoryRead() || IsExclusiveMemoryRead();
}
bool Inst::IsMemoryWrite() const {
return IsSharedMemoryWrite() || IsExclusiveMemoryWrite();
}
bool Inst::IsMemoryReadOrWrite() const {
return IsMemoryRead() || IsMemoryWrite();
}
bool Inst::ReadsFromCPSR() const {
switch (op) {
case Opcode::A32GetCpsr:
case Opcode::A32GetNFlag:
case Opcode::A32GetZFlag:
case Opcode::A32GetCFlag:
case Opcode::A32GetVFlag:
case Opcode::A32GetGEFlags:
case Opcode::A64GetCFlag:
case Opcode::A64GetNZCVRaw:
case Opcode::ConditionalSelect32:
case Opcode::ConditionalSelect64:
case Opcode::ConditionalSelectNZCV:
return true;
default:
return false;
}
}
bool Inst::WritesToCPSR() const {
switch (op) {
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:
case Opcode::A64SetNZCVRaw:
case Opcode::A64SetNZCV:
return true;
default:
return false;
}
}
bool Inst::WritesToSystemRegister() const {
switch (op) {
case Opcode::A64SetTPIDR:
return true;
default:
return false;
}
}
bool Inst::ReadsFromCoreRegister() const {
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;
}
}
bool Inst::WritesToCoreRegister() const {
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;
}
}
bool Inst::ReadsFromFPCR() const {
switch (op) {
case Opcode::A32GetFpscr:
case Opcode::A32GetFpscrNZCV:
case Opcode::A64GetFPCR:
return true;
default:
return false;
}
}
bool Inst::WritesToFPCR() const {
switch (op) {
case Opcode::A32SetFpscr:
case Opcode::A32SetFpscrNZCV:
case Opcode::A64SetFPCR:
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) {
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::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;
}
}
bool Inst::ReadsFromFPSRCumulativeSaturationBit() const {
return false;
}
bool Inst::WritesToFPSRCumulativeSaturationBit() const {
switch (op) {
case Opcode::A64OrQC:
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::VectorSignedSaturatedDoublingMultiply16:
case Opcode::VectorSignedSaturatedDoublingMultiply32:
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;
}
}
bool Inst::CausesCPUException() const {
return op == Opcode::Breakpoint ||
op == Opcode::A32CallSupervisor ||
op == Opcode::A32ExceptionRaised ||
op == Opcode::A64CallSupervisor ||
op == Opcode::A64ExceptionRaised;
}
bool Inst::AltersExclusiveState() const {
return op == Opcode::A32ClearExclusive ||
op == Opcode::A64ClearExclusive ||
IsExclusiveMemoryRead() ||
IsExclusiveMemoryWrite();
}
bool Inst::IsCoprocessorInstruction() const {
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;
}
}
bool Inst::IsSetCheckBitOperation() const {
return op == Opcode::A32SetCheckBit ||
op == Opcode::A64SetCheckBit;
}
bool Inst::MayHaveSideEffects() const {
return op == Opcode::PushRSB ||
op == Opcode::A64DataCacheOperationRaised ||
IsSetCheckBitOperation() ||
IsBarrier() ||
CausesCPUException() ||
WritesToCoreRegister() ||
WritesToSystemRegister() ||
WritesToCPSR() ||
WritesToFPCR() ||
WritesToFPSR() ||
AltersExclusiveState() ||
IsMemoryWrite() ||
IsCoprocessorInstruction();
}
bool Inst::IsAPseudoOperation() const {
switch (op) {
case Opcode::GetCarryFromOp:
case Opcode::GetOverflowFromOp:
case Opcode::GetGEFromOp:
case Opcode::GetNZCVFromOp:
case Opcode::GetUpperFromOp:
case Opcode::GetLowerFromOp:
return true;
default:
return false;
}
}
bool Inst::MayGetNZCVFromOp() const {
switch (op) {
case Opcode::Add32:
case Opcode::Add64:
case Opcode::Sub32:
case Opcode::Sub64:
case Opcode::And32:
case Opcode::And64:
case Opcode::Eor32:
case Opcode::Eor64:
case Opcode::Or32:
case Opcode::Or64:
case Opcode::Not32:
case Opcode::Not64:
return true;
default:
return false;
}
}
bool Inst::AreAllArgsImmediates() const {
return std::all_of(args.begin(), args.begin() + NumArgs(), [](const auto& value){ return value.IsImmediate(); });
}
bool Inst::HasAssociatedPseudoOperation() const {
return carry_inst || overflow_inst || ge_inst || nzcv_inst || upper_inst || lower_inst;
}
Inst* Inst::GetAssociatedPseudoOperation(Opcode opcode) {
// This is faster than doing a search through the block.
switch (opcode) {
case Opcode::GetCarryFromOp:
ASSERT(!carry_inst || carry_inst->GetOpcode() == Opcode::GetCarryFromOp);
return carry_inst;
case Opcode::GetOverflowFromOp:
ASSERT(!overflow_inst || overflow_inst->GetOpcode() == Opcode::GetOverflowFromOp);
return overflow_inst;
case Opcode::GetGEFromOp:
ASSERT(!ge_inst || ge_inst->GetOpcode() == Opcode::GetGEFromOp);
return ge_inst;
case Opcode::GetNZCVFromOp:
ASSERT(!nzcv_inst || nzcv_inst->GetOpcode() == Opcode::GetNZCVFromOp);
return nzcv_inst;
case Opcode::GetUpperFromOp:
ASSERT(!upper_inst || upper_inst->GetOpcode() == Opcode::GetUpperFromOp);
return upper_inst;
case Opcode::GetLowerFromOp:
ASSERT(!lower_inst || lower_inst->GetOpcode() == Opcode::GetLowerFromOp);
return lower_inst;
default:
break;
}
ASSERT_FALSE("Not a valid pseudo-operation");
}
Type Inst::GetType() const {
if (op == Opcode::Identity)
return args[0].GetType();
return GetTypeOf(op);
}
size_t Inst::NumArgs() const {
return GetNumArgsOf(op);
}
Value Inst::GetArg(size_t index) const {
ASSERT_MSG(index < GetNumArgsOf(op), "Inst::GetArg: index {} >= number of arguments of {} ({})", index, op, GetNumArgsOf(op));
ASSERT_MSG(!args[index].IsEmpty() || GetArgTypeOf(op, index) == IR::Type::Opaque, "Inst::GetArg: index {} is empty", index, args[index].GetType());
return args[index];
}
void Inst::SetArg(size_t index, Value value) {
ASSERT_MSG(index < GetNumArgsOf(op), "Inst::SetArg: index {} >= number of arguments of {} ({})", index, op, GetNumArgsOf(op));
ASSERT_MSG(AreTypesCompatible(value.GetType(), GetArgTypeOf(op, index)), "Inst::SetArg: type {} of argument {} not compatible with operation {} ({})", value.GetType(), index, op, GetArgTypeOf(op, index));
if (!args[index].IsImmediate()) {
UndoUse(args[index]);
}
if (!value.IsImmediate()) {
Use(value);
}
args[index] = value;
}
void Inst::Invalidate() {
ClearArgs();
op = Opcode::Void;
}
void Inst::ClearArgs() {
for (auto& value : args) {
if (!value.IsImmediate()) {
UndoUse(value);
}
value = {};
}
}
void Inst::ReplaceUsesWith(Value replacement) {
Invalidate();
op = Opcode::Identity;
if (!replacement.IsImmediate()) {
Use(replacement);
}
args[0] = replacement;
}
void Inst::Use(const Value& value) {
value.GetInst()->use_count++;
switch (op){
case Opcode::GetCarryFromOp:
ASSERT_MSG(!value.GetInst()->carry_inst, "Only one of each type of pseudo-op allowed");
value.GetInst()->carry_inst = this;
break;
case Opcode::GetOverflowFromOp:
ASSERT_MSG(!value.GetInst()->overflow_inst, "Only one of each type of pseudo-op allowed");
value.GetInst()->overflow_inst = this;
break;
case Opcode::GetGEFromOp:
ASSERT_MSG(!value.GetInst()->ge_inst, "Only one of each type of pseudo-op allowed");
value.GetInst()->ge_inst = this;
break;
case Opcode::GetNZCVFromOp:
ASSERT_MSG(!value.GetInst()->nzcv_inst, "Only one of each type of pseudo-op allowed");
ASSERT_MSG(value.GetInst()->MayGetNZCVFromOp(), "This value doesn't support the GetNZCVFromOp pseduo-op");
value.GetInst()->nzcv_inst = this;
break;
case Opcode::GetUpperFromOp:
ASSERT_MSG(!value.GetInst()->upper_inst, "Only one of each type of pseudo-op allowed");
value.GetInst()->upper_inst = this;
break;
case Opcode::GetLowerFromOp:
ASSERT_MSG(!value.GetInst()->lower_inst, "Only one of each type of pseudo-op allowed");
value.GetInst()->lower_inst = this;
break;
default:
break;
}
}
void Inst::UndoUse(const Value& value) {
value.GetInst()->use_count--;
switch (op){
case Opcode::GetCarryFromOp:
ASSERT(value.GetInst()->carry_inst->GetOpcode() == Opcode::GetCarryFromOp);
value.GetInst()->carry_inst = nullptr;
break;
case Opcode::GetOverflowFromOp:
ASSERT(value.GetInst()->overflow_inst->GetOpcode() == Opcode::GetOverflowFromOp);
value.GetInst()->overflow_inst = nullptr;
break;
case Opcode::GetGEFromOp:
ASSERT(value.GetInst()->ge_inst->GetOpcode() == Opcode::GetGEFromOp);
value.GetInst()->ge_inst = nullptr;
break;
case Opcode::GetNZCVFromOp:
ASSERT(value.GetInst()->nzcv_inst->GetOpcode() == Opcode::GetNZCVFromOp);
value.GetInst()->nzcv_inst = nullptr;
break;
case Opcode::GetUpperFromOp:
ASSERT(value.GetInst()->upper_inst->GetOpcode() == Opcode::GetUpperFromOp);
value.GetInst()->upper_inst = nullptr;
break;
case Opcode::GetLowerFromOp:
ASSERT(value.GetInst()->lower_inst->GetOpcode() == Opcode::GetLowerFromOp);
value.GetInst()->lower_inst = nullptr;
break;
default:
break;
}
}
} // namespace Dynarmic::IR

View File

@@ -0,0 +1,164 @@
/* This file is part of the dynarmic project.
* Copyright (c) 2016 MerryMage
* SPDX-License-Identifier: 0BSD
*/
#pragma once
#include <array>
#include "common/common_types.h"
#include "common/intrusive_list.h"
#include "frontend/ir/value.h"
namespace Dynarmic::IR {
enum class Opcode;
enum class Type;
constexpr size_t max_arg_count = 4;
/**
* A representation of a microinstruction. A single ARM/Thumb instruction may be
* converted into zero or more microinstructions.
*/
class Inst final : public Common::IntrusiveListNode<Inst> {
public:
explicit Inst(Opcode op) : op(op) {}
/// Determines whether or not this instruction performs an arithmetic shift.
bool IsArithmeticShift() const;
/// Determines whether or not this instruction performs a logical shift.
bool IsLogicalShift() const;
/// Determines whether or not this instruction performs a circular shift.
bool IsCircularShift() const;
/// Determines whether or not this instruction performs any kind of shift.
bool IsShift() const;
/// Determines whether or not this instruction is a form of barrier.
bool IsBarrier() const;
/// Determines whether or not this instruction performs a shared memory read.
bool IsSharedMemoryRead() const;
/// Determines whether or not this instruction performs a shared memory write.
bool IsSharedMemoryWrite() const;
/// Determines whether or not this instruction performs a shared memory read or write.
bool IsSharedMemoryReadOrWrite() const;
/// Determines whether or not this instruction performs an atomic memory read.
bool IsExclusiveMemoryRead() const;
/// Determines whether or not this instruction performs an atomic memory write.
bool IsExclusiveMemoryWrite() const;
/// Determines whether or not this instruction performs any kind of memory read.
bool IsMemoryRead() const;
/// Determines whether or not this instruction performs any kind of memory write.
bool IsMemoryWrite() const;
/// Determines whether or not this instruction performs any kind of memory access.
bool IsMemoryReadOrWrite() const;
/// Determines whether or not this instruction reads from the CPSR.
bool ReadsFromCPSR() const;
/// Determines whether or not this instruction writes to the CPSR.
bool WritesToCPSR() const;
/// Determines whether or not this instruction writes to a system register.
bool WritesToSystemRegister() const;
/// Determines whether or not this instruction reads from a core register.
bool ReadsFromCoreRegister() const;
/// Determines whether or not this instruction writes to a core register.
bool WritesToCoreRegister() const;
/// Determines whether or not this instruction reads from the FPCR.
bool ReadsFromFPCR() const;
/// Determines whether or not this instruction writes to the FPCR.
bool WritesToFPCR() const;
/// Determines whether or not this instruction reads from the FPSR.
bool ReadsFromFPSR() const;
/// Determines whether or not this instruction writes to the FPSR.
bool WritesToFPSR() const;
/// Determines whether or not this instruction reads from the FPSR cumulative exception bits.
bool ReadsFromFPSRCumulativeExceptionBits() const;
/// Determines whether or not this instruction writes to the FPSR cumulative exception bits.
bool WritesToFPSRCumulativeExceptionBits() const;
/// Determines whether or not this instruction both reads from and writes to the FPSR cumulative exception bits.
bool ReadsFromAndWritesToFPSRCumulativeExceptionBits() const;
/// Determines whether or not this instruction reads from the FPSR cumulative saturation bit.
bool ReadsFromFPSRCumulativeSaturationBit() const;
/// Determines whether or not this instruction writes to the FPSR cumulative saturation bit.
bool WritesToFPSRCumulativeSaturationBit() const;
/// Determines whether or not this instruction alters memory-exclusivity.
bool AltersExclusiveState() const;
/// Determines whether or not this instruction accesses a coprocessor.
bool IsCoprocessorInstruction() const;
/// Determines whether or not this instruction causes a CPU exception.
bool CausesCPUException() const;
/// Determines whether or not this instruction is a SetCheckBit operation.
bool IsSetCheckBitOperation() const;
/// Determines whether or not this instruction may have side-effects.
bool MayHaveSideEffects() const;
/// Determines whether or not this instruction is a pseduo-instruction.
/// Pseudo-instructions depend on their parent instructions for their semantics.
bool IsAPseudoOperation() const;
/// Determines whether or not this instruction supports the GetNZCVFromOp pseudo-operation.
bool MayGetNZCVFromOp() const;
/// Determines if all arguments of this instruction are immediates.
bool AreAllArgsImmediates() const;
size_t UseCount() const { return use_count; }
bool HasUses() const { return use_count > 0; }
/// Determines if there is a pseudo-operation associated with this instruction.
bool HasAssociatedPseudoOperation() const;
/// Gets a pseudo-operation associated with this instruction.
Inst* GetAssociatedPseudoOperation(Opcode opcode);
/// Get the microop this microinstruction represents.
Opcode GetOpcode() const { return op; }
/// Get the type this instruction returns.
Type GetType() const;
/// Get the number of arguments this instruction has.
size_t NumArgs() const;
Value GetArg(size_t index) const;
void SetArg(size_t index, Value value);
void Invalidate();
void ClearArgs();
void ReplaceUsesWith(Value replacement);
private:
void Use(const Value& value);
void UndoUse(const Value& value);
Opcode op;
size_t use_count = 0;
std::array<Value, max_arg_count> args;
// Pointers to related pseudooperations:
// Since not all combinations are possible, we use a union to save space
union {
Inst* carry_inst = nullptr;
Inst* ge_inst;
Inst* upper_inst;
};
Inst* overflow_inst = nullptr;
union {
Inst* nzcv_inst = nullptr;
Inst* lower_inst;
};
};
} // namespace Dynarmic::IR

View File

@@ -0,0 +1,78 @@
/* This file is part of the dynarmic project.
* Copyright (c) 2016 MerryMage
* SPDX-License-Identifier: 0BSD
*/
#include <array>
#include <ostream>
#include <string>
#include <vector>
#include <fmt/format.h>
#include <fmt/ostream.h>
#include "frontend/ir/opcodes.h"
#include "frontend/ir/type.h"
namespace Dynarmic::IR {
// Opcode information
namespace OpcodeInfo {
struct Meta {
const char* name;
Type type;
std::vector<Type> arg_types;
};
constexpr Type Void = Type::Void;
constexpr Type A32Reg = Type::A32Reg;
constexpr Type A32ExtReg = Type::A32ExtReg;
constexpr Type A64Reg = Type::A64Reg;
constexpr Type A64Vec = Type::A64Vec;
constexpr Type Opaque = Type::Opaque;
constexpr Type U1 = Type::U1;
constexpr Type U8 = Type::U8;
constexpr Type U16 = Type::U16;
constexpr Type U32 = Type::U32;
constexpr Type U64 = Type::U64;
constexpr Type U128 = Type::U128;
constexpr Type CoprocInfo = Type::CoprocInfo;
constexpr Type NZCV = Type::NZCVFlags;
constexpr Type Cond = Type::Cond;
constexpr Type Table = Type::Table;
static const std::array opcode_info {
#define OPCODE(name, type, ...) Meta{#name, type, {__VA_ARGS__}},
#define A32OPC(name, type, ...) Meta{#name, type, {__VA_ARGS__}},
#define A64OPC(name, type, ...) Meta{#name, type, {__VA_ARGS__}},
#include "opcodes.inc"
#undef OPCODE
#undef A32OPC
#undef A64OPC
};
} // namespace OpcodeInfo
Type GetTypeOf(Opcode op) {
return OpcodeInfo::opcode_info.at(static_cast<size_t>(op)).type;
}
size_t GetNumArgsOf(Opcode op) {
return OpcodeInfo::opcode_info.at(static_cast<size_t>(op)).arg_types.size();
}
Type GetArgTypeOf(Opcode op, size_t arg_index) {
return OpcodeInfo::opcode_info.at(static_cast<size_t>(op)).arg_types.at(arg_index);
}
std::string GetNameOf(Opcode op) {
return OpcodeInfo::opcode_info.at(static_cast<size_t>(op)).name;
}
std::ostream& operator<<(std::ostream& o, Opcode opcode) {
return o << GetNameOf(opcode);
}
} // namespace Dynarmic::IR

48
externals/dynarmic/src/frontend/ir/opcodes.h vendored Executable file
View File

@@ -0,0 +1,48 @@
/* This file is part of the dynarmic project.
* Copyright (c) 2016 MerryMage
* SPDX-License-Identifier: 0BSD
*/
#pragma once
#include <iosfwd>
#include <string>
#include "common/common_types.h"
namespace Dynarmic::IR {
enum class Type;
/**
* 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);
/// Get return type of an opcode
Type GetTypeOf(Opcode op);
/// Get the number of arguments an opcode accepts
size_t GetNumArgsOf(Opcode op);
/// Get the required type of an argument of an opcode
Type GetArgTypeOf(Opcode op, size_t arg_index);
/// Get the name of an opcode.
std::string GetNameOf(Opcode op);
std::ostream& operator<<(std::ostream& o, Opcode opcode);
} // namespace Dynarmic::IR

714
externals/dynarmic/src/frontend/ir/opcodes.inc vendored Executable file
View File

@@ -0,0 +1,714 @@
// opcode name, return type, arg1 type, arg2 type, arg3 type, arg4 type, ...
OPCODE(Void, Void, )
OPCODE(Identity, Opaque, Opaque )
OPCODE(Breakpoint, Void, )
// A32 Context getters/setters
A32OPC(SetCheckBit, Void, U1 )
A32OPC(GetRegister, U32, A32Reg )
A32OPC(GetExtendedRegister32, U32, A32ExtReg )
A32OPC(GetExtendedRegister64, U64, A32ExtReg )
A32OPC(GetVector, U128, A32ExtReg )
A32OPC(SetRegister, Void, A32Reg, U32 )
A32OPC(SetExtendedRegister32, Void, A32ExtReg, U32 )
A32OPC(SetExtendedRegister64, Void, A32ExtReg, U64 )
A32OPC(SetVector, Void, A32ExtReg, U128 )
A32OPC(GetCpsr, U32, )
A32OPC(SetCpsr, Void, U32 )
A32OPC(SetCpsrNZCV, Void, U32 )
A32OPC(SetCpsrNZCVQ, Void, U32 )
A32OPC(GetNFlag, U1, )
A32OPC(SetNFlag, Void, U1 )
A32OPC(GetZFlag, U1, )
A32OPC(SetZFlag, Void, U1 )
A32OPC(GetCFlag, U1, )
A32OPC(SetCFlag, Void, U1 )
A32OPC(GetVFlag, U1, )
A32OPC(SetVFlag, Void, U1 )
A32OPC(OrQFlag, Void, U1 )
A32OPC(GetGEFlags, U32, )
A32OPC(SetGEFlags, Void, U32 )
A32OPC(SetGEFlagsCompressed, Void, U32 )
A32OPC(BXWritePC, Void, U32 )
A32OPC(CallSupervisor, Void, U32 )
A32OPC(ExceptionRaised, Void, U32, U64 )
A32OPC(DataSynchronizationBarrier, Void, )
A32OPC(DataMemoryBarrier, Void, )
A32OPC(InstructionSynchronizationBarrier, Void, )
A32OPC(GetFpscr, U32, )
A32OPC(SetFpscr, Void, U32, )
A32OPC(GetFpscrNZCV, U32, )
A32OPC(SetFpscrNZCV, Void, NZCV )
// A64 Context getters/setters
A64OPC(SetCheckBit, Void, U1 )
A64OPC(GetCFlag, U1, )
A64OPC(GetNZCVRaw, U32, )
A64OPC(SetNZCVRaw, Void, U32 )
A64OPC(SetNZCV, Void, NZCV )
A64OPC(GetW, U32, A64Reg )
A64OPC(GetX, U64, A64Reg )
A64OPC(GetS, U128, A64Vec )
A64OPC(GetD, U128, A64Vec )
A64OPC(GetQ, U128, A64Vec )
A64OPC(GetSP, U64, )
A64OPC(GetFPCR, U32, )
A64OPC(GetFPSR, U32, )
A64OPC(SetW, Void, A64Reg, U32 )
A64OPC(SetX, Void, A64Reg, U64 )
A64OPC(SetS, Void, A64Vec, U128 )
A64OPC(SetD, Void, A64Vec, U128 )
A64OPC(SetQ, Void, A64Vec, U128 )
A64OPC(SetSP, Void, U64 )
A64OPC(SetFPCR, Void, U32 )
A64OPC(SetFPSR, Void, U32 )
A64OPC(OrQC, Void, U1 )
A64OPC(SetPC, Void, U64 )
A64OPC(CallSupervisor, Void, U32 )
A64OPC(ExceptionRaised, Void, U64, U64 )
A64OPC(DataCacheOperationRaised, Void, U64, U64 )
A64OPC(DataSynchronizationBarrier, Void, )
A64OPC(DataMemoryBarrier, Void, )
A64OPC(InstructionSynchronizationBarrier, Void, )
A64OPC(GetCNTFRQ, U32, )
A64OPC(GetCNTPCT, U64, )
A64OPC(GetCTR, U32, )
A64OPC(GetDCZID, U32, )
A64OPC(GetTPIDR, U64, )
A64OPC(GetTPIDRRO, U64, )
A64OPC(SetTPIDR, Void, U64 )
// Hints
OPCODE(PushRSB, Void, U64 )
// Pseudo-operation, handled specially at final emit
OPCODE(GetCarryFromOp, U1, Opaque )
OPCODE(GetOverflowFromOp, U1, Opaque )
OPCODE(GetGEFromOp, U32, Opaque )
OPCODE(GetNZCVFromOp, NZCV, Opaque )
OPCODE(GetUpperFromOp, U128, Opaque )
OPCODE(GetLowerFromOp, U128, Opaque )
OPCODE(NZCVFromPackedFlags, NZCV, U32 )
// Calculations
OPCODE(Pack2x32To1x64, U64, U32, U32 )
OPCODE(Pack2x64To1x128, U128, U64, U64 )
OPCODE(LeastSignificantWord, U32, U64 )
OPCODE(LeastSignificantHalf, U16, U32 )
OPCODE(LeastSignificantByte, U8, U32 )
OPCODE(MostSignificantWord, U32, U64 )
OPCODE(MostSignificantBit, U1, U32 )
OPCODE(IsZero32, U1, U32 )
OPCODE(IsZero64, U1, U64 )
OPCODE(TestBit, U1, U64, U8 )
OPCODE(ConditionalSelect32, U32, Cond, U32, U32 )
OPCODE(ConditionalSelect64, U64, Cond, U64, U64 )
OPCODE(ConditionalSelectNZCV, NZCV, Cond, NZCV, NZCV )
OPCODE(LogicalShiftLeft32, U32, U32, U8, U1 )
OPCODE(LogicalShiftLeft64, U64, U64, U8 )
OPCODE(LogicalShiftRight32, U32, U32, U8, U1 )
OPCODE(LogicalShiftRight64, U64, U64, U8 )
OPCODE(ArithmeticShiftRight32, U32, U32, U8, U1 )
OPCODE(ArithmeticShiftRight64, U64, U64, U8 )
OPCODE(RotateRight32, U32, U32, U8, U1 )
OPCODE(RotateRight64, U64, U64, U8 )
OPCODE(RotateRightExtended, U32, U32, U1 )
OPCODE(LogicalShiftLeftMasked32, U32, U32, U32 )
OPCODE(LogicalShiftLeftMasked64, U64, U64, U64 )
OPCODE(LogicalShiftRightMasked32, U32, U32, U32 )
OPCODE(LogicalShiftRightMasked64, U64, U64, U64 )
OPCODE(ArithmeticShiftRightMasked32, U32, U32, U32 )
OPCODE(ArithmeticShiftRightMasked64, U64, U64, U64 )
OPCODE(RotateRightMasked32, U32, U32, U32 )
OPCODE(RotateRightMasked64, U64, U64, U64 )
OPCODE(Add32, U32, U32, U32, U1 )
OPCODE(Add64, U64, U64, U64, U1 )
OPCODE(Sub32, U32, U32, U32, U1 )
OPCODE(Sub64, U64, U64, U64, U1 )
OPCODE(Mul32, U32, U32, U32 )
OPCODE(Mul64, U64, U64, U64 )
OPCODE(SignedMultiplyHigh64, U64, U64, U64 )
OPCODE(UnsignedMultiplyHigh64, U64, U64, U64 )
OPCODE(UnsignedDiv32, U32, U32, U32 )
OPCODE(UnsignedDiv64, U64, U64, U64 )
OPCODE(SignedDiv32, U32, U32, U32 )
OPCODE(SignedDiv64, U64, U64, U64 )
OPCODE(And32, U32, U32, U32 )
OPCODE(And64, U64, U64, U64 )
OPCODE(Eor32, U32, U32, U32 )
OPCODE(Eor64, U64, U64, U64 )
OPCODE(Or32, U32, U32, U32 )
OPCODE(Or64, U64, U64, U64 )
OPCODE(Not32, U32, U32 )
OPCODE(Not64, U64, U64 )
OPCODE(SignExtendByteToWord, U32, U8 )
OPCODE(SignExtendHalfToWord, U32, U16 )
OPCODE(SignExtendByteToLong, U64, U8 )
OPCODE(SignExtendHalfToLong, U64, U16 )
OPCODE(SignExtendWordToLong, U64, U32 )
OPCODE(ZeroExtendByteToWord, U32, U8 )
OPCODE(ZeroExtendHalfToWord, U32, U16 )
OPCODE(ZeroExtendByteToLong, U64, U8 )
OPCODE(ZeroExtendHalfToLong, U64, U16 )
OPCODE(ZeroExtendWordToLong, U64, U32 )
OPCODE(ZeroExtendLongToQuad, U128, U64 )
OPCODE(ByteReverseWord, U32, U32 )
OPCODE(ByteReverseHalf, U16, U16 )
OPCODE(ByteReverseDual, U64, U64 )
OPCODE(CountLeadingZeros32, U32, U32 )
OPCODE(CountLeadingZeros64, U64, U64 )
OPCODE(ExtractRegister32, U32, U32, U32, U8 )
OPCODE(ExtractRegister64, U64, U64, U64, U8 )
OPCODE(ReplicateBit32, U32, U32, U8 )
OPCODE(ReplicateBit64, U64, U64, U8 )
OPCODE(MaxSigned32, U32, U32, U32 )
OPCODE(MaxSigned64, U64, U64, U64 )
OPCODE(MaxUnsigned32, U32, U32, U32 )
OPCODE(MaxUnsigned64, U64, U64, U64 )
OPCODE(MinSigned32, U32, U32, U32 )
OPCODE(MinSigned64, U64, U64, U64 )
OPCODE(MinUnsigned32, U32, U32, U32 )
OPCODE(MinUnsigned64, U64, U64, U64 )
// Saturated instructions
OPCODE(SignedSaturatedAdd8, U8, U8, U8 )
OPCODE(SignedSaturatedAdd16, U16, U16, U16 )
OPCODE(SignedSaturatedAdd32, U32, U32, U32 )
OPCODE(SignedSaturatedAdd64, U64, U64, U64 )
OPCODE(SignedSaturatedDoublingMultiplyReturnHigh16, U16, U16, U16 )
OPCODE(SignedSaturatedDoublingMultiplyReturnHigh32, U32, U32, U32 )
OPCODE(SignedSaturatedSub8, U8, U8, U8 )
OPCODE(SignedSaturatedSub16, U16, U16, U16 )
OPCODE(SignedSaturatedSub32, U32, U32, U32 )
OPCODE(SignedSaturatedSub64, U64, U64, U64 )
OPCODE(SignedSaturation, U32, U32, U8 )
OPCODE(UnsignedSaturatedAdd8, U8, U8, U8 )
OPCODE(UnsignedSaturatedAdd16, U16, U16, U16 )
OPCODE(UnsignedSaturatedAdd32, U32, U32, U32 )
OPCODE(UnsignedSaturatedAdd64, U64, U64, U64 )
OPCODE(UnsignedSaturatedSub8, U8, U8, U8 )
OPCODE(UnsignedSaturatedSub16, U16, U16, U16 )
OPCODE(UnsignedSaturatedSub32, U32, U32, U32 )
OPCODE(UnsignedSaturatedSub64, U64, U64, U64 )
OPCODE(UnsignedSaturation, U32, U32, U8 )
// Vector saturated instructions
OPCODE(VectorSignedSaturatedAdd8, U128, U128, U128 )
OPCODE(VectorSignedSaturatedAdd16, U128, U128, U128 )
OPCODE(VectorSignedSaturatedAdd32, U128, U128, U128 )
OPCODE(VectorSignedSaturatedAdd64, U128, U128, U128 )
OPCODE(VectorSignedSaturatedSub8, U128, U128, U128 )
OPCODE(VectorSignedSaturatedSub16, U128, U128, U128 )
OPCODE(VectorSignedSaturatedSub32, U128, U128, U128 )
OPCODE(VectorSignedSaturatedSub64, U128, U128, U128 )
OPCODE(VectorUnsignedSaturatedAdd8, U128, U128, U128 )
OPCODE(VectorUnsignedSaturatedAdd16, U128, U128, U128 )
OPCODE(VectorUnsignedSaturatedAdd32, U128, U128, U128 )
OPCODE(VectorUnsignedSaturatedAdd64, U128, U128, U128 )
OPCODE(VectorUnsignedSaturatedSub8, U128, U128, U128 )
OPCODE(VectorUnsignedSaturatedSub16, U128, U128, U128 )
OPCODE(VectorUnsignedSaturatedSub32, U128, U128, U128 )
OPCODE(VectorUnsignedSaturatedSub64, U128, U128, U128 )
// Packed instructions
OPCODE(PackedAddU8, U32, U32, U32 )
OPCODE(PackedAddS8, U32, U32, U32 )
OPCODE(PackedSubU8, U32, U32, U32 )
OPCODE(PackedSubS8, U32, U32, U32 )
OPCODE(PackedAddU16, U32, U32, U32 )
OPCODE(PackedAddS16, U32, U32, U32 )
OPCODE(PackedSubU16, U32, U32, U32 )
OPCODE(PackedSubS16, U32, U32, U32 )
OPCODE(PackedAddSubU16, U32, U32, U32 )
OPCODE(PackedAddSubS16, U32, U32, U32 )
OPCODE(PackedSubAddU16, U32, U32, U32 )
OPCODE(PackedSubAddS16, U32, U32, U32 )
OPCODE(PackedHalvingAddU8, U32, U32, U32 )
OPCODE(PackedHalvingAddS8, U32, U32, U32 )
OPCODE(PackedHalvingSubU8, U32, U32, U32 )
OPCODE(PackedHalvingSubS8, U32, U32, U32 )
OPCODE(PackedHalvingAddU16, U32, U32, U32 )
OPCODE(PackedHalvingAddS16, U32, U32, U32 )
OPCODE(PackedHalvingSubU16, U32, U32, U32 )
OPCODE(PackedHalvingSubS16, U32, U32, U32 )
OPCODE(PackedHalvingAddSubU16, U32, U32, U32 )
OPCODE(PackedHalvingAddSubS16, U32, U32, U32 )
OPCODE(PackedHalvingSubAddU16, U32, U32, U32 )
OPCODE(PackedHalvingSubAddS16, U32, U32, U32 )
OPCODE(PackedSaturatedAddU8, U32, U32, U32 )
OPCODE(PackedSaturatedAddS8, U32, U32, U32 )
OPCODE(PackedSaturatedSubU8, U32, U32, U32 )
OPCODE(PackedSaturatedSubS8, U32, U32, U32 )
OPCODE(PackedSaturatedAddU16, U32, U32, U32 )
OPCODE(PackedSaturatedAddS16, U32, U32, U32 )
OPCODE(PackedSaturatedSubU16, U32, U32, U32 )
OPCODE(PackedSaturatedSubS16, U32, U32, U32 )
OPCODE(PackedAbsDiffSumS8, U32, U32, U32 )
OPCODE(PackedSelect, U32, U32, U32, U32 )
// CRC instructions
OPCODE(CRC32Castagnoli8, U32, U32, U32 )
OPCODE(CRC32Castagnoli16, U32, U32, U32 )
OPCODE(CRC32Castagnoli32, U32, U32, U32 )
OPCODE(CRC32Castagnoli64, U32, U32, U64 )
OPCODE(CRC32ISO8, U32, U32, U32 )
OPCODE(CRC32ISO16, U32, U32, U32 )
OPCODE(CRC32ISO32, U32, U32, U32 )
OPCODE(CRC32ISO64, U32, U32, U64 )
// AES instructions
OPCODE(AESDecryptSingleRound, U128, U128 )
OPCODE(AESEncryptSingleRound, U128, U128 )
OPCODE(AESInverseMixColumns, U128, U128 )
OPCODE(AESMixColumns, U128, U128 )
// SM4 instructions
OPCODE(SM4AccessSubstitutionBox, U8, U8 )
// Vector instructions
OPCODE(VectorGetElement8, U8, U128, U8 )
OPCODE(VectorGetElement16, U16, U128, U8 )
OPCODE(VectorGetElement32, U32, U128, U8 )
OPCODE(VectorGetElement64, U64, U128, U8 )
OPCODE(VectorSetElement8, U128, U128, U8, U8 )
OPCODE(VectorSetElement16, U128, U128, U8, U16 )
OPCODE(VectorSetElement32, U128, U128, U8, U32 )
OPCODE(VectorSetElement64, U128, U128, U8, U64 )
OPCODE(VectorAbs8, U128, U128 )
OPCODE(VectorAbs16, U128, U128 )
OPCODE(VectorAbs32, U128, U128 )
OPCODE(VectorAbs64, U128, U128 )
OPCODE(VectorAdd8, U128, U128, U128 )
OPCODE(VectorAdd16, U128, U128, U128 )
OPCODE(VectorAdd32, U128, U128, U128 )
OPCODE(VectorAdd64, U128, U128, U128 )
OPCODE(VectorAnd, U128, U128, U128 )
OPCODE(VectorArithmeticShiftRight8, U128, U128, U8 )
OPCODE(VectorArithmeticShiftRight16, U128, U128, U8 )
OPCODE(VectorArithmeticShiftRight32, U128, U128, U8 )
OPCODE(VectorArithmeticShiftRight64, U128, U128, U8 )
OPCODE(VectorArithmeticVShift8, U128, U128, U128 )
OPCODE(VectorArithmeticVShift16, U128, U128, U128 )
OPCODE(VectorArithmeticVShift32, U128, U128, U128 )
OPCODE(VectorArithmeticVShift64, U128, U128, U128 )
OPCODE(VectorBroadcastLower8, U128, U8 )
OPCODE(VectorBroadcastLower16, U128, U16 )
OPCODE(VectorBroadcastLower32, U128, U32 )
OPCODE(VectorBroadcast8, U128, U8 )
OPCODE(VectorBroadcast16, U128, U16 )
OPCODE(VectorBroadcast32, U128, U32 )
OPCODE(VectorBroadcast64, U128, U64 )
OPCODE(VectorCountLeadingZeros8, U128, U128 )
OPCODE(VectorCountLeadingZeros16, U128, U128 )
OPCODE(VectorCountLeadingZeros32, U128, U128 )
OPCODE(VectorDeinterleaveEven8, U128, U128, U128 )
OPCODE(VectorDeinterleaveEven16, U128, U128, U128 )
OPCODE(VectorDeinterleaveEven32, U128, U128, U128 )
OPCODE(VectorDeinterleaveEven64, U128, U128, U128 )
OPCODE(VectorDeinterleaveEvenLower8, U128, U128, U128 )
OPCODE(VectorDeinterleaveEvenLower16, U128, U128, U128 )
OPCODE(VectorDeinterleaveEvenLower32, U128, U128, U128 )
OPCODE(VectorDeinterleaveEvenLower64, U128, U128, U128 )
OPCODE(VectorDeinterleaveOdd8, U128, U128, U128 )
OPCODE(VectorDeinterleaveOdd16, U128, U128, U128 )
OPCODE(VectorDeinterleaveOdd32, U128, U128, U128 )
OPCODE(VectorDeinterleaveOdd64, U128, U128, U128 )
OPCODE(VectorDeinterleaveOddLower8, U128, U128, U128 )
OPCODE(VectorDeinterleaveOddLower16, U128, U128, U128 )
OPCODE(VectorDeinterleaveOddLower32, U128, U128, U128 )
OPCODE(VectorDeinterleaveOddLower64, U128, U128, U128 )
OPCODE(VectorEor, U128, U128, U128 )
OPCODE(VectorEqual8, U128, U128, U128 )
OPCODE(VectorEqual16, U128, U128, U128 )
OPCODE(VectorEqual32, U128, U128, U128 )
OPCODE(VectorEqual64, U128, U128, U128 )
OPCODE(VectorEqual128, U128, U128, U128 )
OPCODE(VectorExtract, U128, U128, U128, U8 )
OPCODE(VectorExtractLower, U128, U128, U128, U8 )
OPCODE(VectorGreaterS8, U128, U128, U128 )
OPCODE(VectorGreaterS16, U128, U128, U128 )
OPCODE(VectorGreaterS32, U128, U128, U128 )
OPCODE(VectorGreaterS64, U128, U128, U128 )
OPCODE(VectorHalvingAddS8, U128, U128, U128 )
OPCODE(VectorHalvingAddS16, U128, U128, U128 )
OPCODE(VectorHalvingAddS32, U128, U128, U128 )
OPCODE(VectorHalvingAddU8, U128, U128, U128 )
OPCODE(VectorHalvingAddU16, U128, U128, U128 )
OPCODE(VectorHalvingAddU32, U128, U128, U128 )
OPCODE(VectorHalvingSubS8, U128, U128, U128 )
OPCODE(VectorHalvingSubS16, U128, U128, U128 )
OPCODE(VectorHalvingSubS32, U128, U128, U128 )
OPCODE(VectorHalvingSubU8, U128, U128, U128 )
OPCODE(VectorHalvingSubU16, U128, U128, U128 )
OPCODE(VectorHalvingSubU32, U128, U128, U128 )
OPCODE(VectorInterleaveLower8, U128, U128, U128 )
OPCODE(VectorInterleaveLower16, U128, U128, U128 )
OPCODE(VectorInterleaveLower32, U128, U128, U128 )
OPCODE(VectorInterleaveLower64, U128, U128, U128 )
OPCODE(VectorInterleaveUpper8, U128, U128, U128 )
OPCODE(VectorInterleaveUpper16, U128, U128, U128 )
OPCODE(VectorInterleaveUpper32, U128, U128, U128 )
OPCODE(VectorInterleaveUpper64, U128, U128, U128 )
OPCODE(VectorLogicalShiftLeft8, U128, U128, U8 )
OPCODE(VectorLogicalShiftLeft16, U128, U128, U8 )
OPCODE(VectorLogicalShiftLeft32, U128, U128, U8 )
OPCODE(VectorLogicalShiftLeft64, U128, U128, U8 )
OPCODE(VectorLogicalShiftRight8, U128, U128, U8 )
OPCODE(VectorLogicalShiftRight16, U128, U128, U8 )
OPCODE(VectorLogicalShiftRight32, U128, U128, U8 )
OPCODE(VectorLogicalShiftRight64, U128, U128, U8 )
OPCODE(VectorLogicalVShift8, U128, U128, U128 )
OPCODE(VectorLogicalVShift16, U128, U128, U128 )
OPCODE(VectorLogicalVShift32, U128, U128, U128 )
OPCODE(VectorLogicalVShift64, U128, U128, U128 )
OPCODE(VectorMaxS8, U128, U128, U128 )
OPCODE(VectorMaxS16, U128, U128, U128 )
OPCODE(VectorMaxS32, U128, U128, U128 )
OPCODE(VectorMaxS64, U128, U128, U128 )
OPCODE(VectorMaxU8, U128, U128, U128 )
OPCODE(VectorMaxU16, U128, U128, U128 )
OPCODE(VectorMaxU32, U128, U128, U128 )
OPCODE(VectorMaxU64, U128, U128, U128 )
OPCODE(VectorMinS8, U128, U128, U128 )
OPCODE(VectorMinS16, U128, U128, U128 )
OPCODE(VectorMinS32, U128, U128, U128 )
OPCODE(VectorMinS64, U128, U128, U128 )
OPCODE(VectorMinU8, U128, U128, U128 )
OPCODE(VectorMinU16, U128, U128, U128 )
OPCODE(VectorMinU32, U128, U128, U128 )
OPCODE(VectorMinU64, U128, U128, U128 )
OPCODE(VectorMultiply8, U128, U128, U128 )
OPCODE(VectorMultiply16, U128, U128, U128 )
OPCODE(VectorMultiply32, U128, U128, U128 )
OPCODE(VectorMultiply64, U128, U128, U128 )
OPCODE(VectorNarrow16, U128, U128 )
OPCODE(VectorNarrow32, U128, U128 )
OPCODE(VectorNarrow64, U128, U128 )
OPCODE(VectorNot, U128, U128 )
OPCODE(VectorOr, U128, U128, U128 )
OPCODE(VectorPairedAddLower8, U128, U128, U128 )
OPCODE(VectorPairedAddLower16, U128, U128, U128 )
OPCODE(VectorPairedAddLower32, U128, U128, U128 )
OPCODE(VectorPairedAddSignedWiden8, U128, U128 )
OPCODE(VectorPairedAddSignedWiden16, U128, U128 )
OPCODE(VectorPairedAddSignedWiden32, U128, U128 )
OPCODE(VectorPairedAddUnsignedWiden8, U128, U128 )
OPCODE(VectorPairedAddUnsignedWiden16, U128, U128 )
OPCODE(VectorPairedAddUnsignedWiden32, U128, U128 )
OPCODE(VectorPairedAdd8, U128, U128, U128 )
OPCODE(VectorPairedAdd16, U128, U128, U128 )
OPCODE(VectorPairedAdd32, U128, U128, U128 )
OPCODE(VectorPairedAdd64, U128, U128, U128 )
OPCODE(VectorPairedMaxS8, U128, U128, U128 )
OPCODE(VectorPairedMaxS16, U128, U128, U128 )
OPCODE(VectorPairedMaxS32, U128, U128, U128 )
OPCODE(VectorPairedMaxU8, U128, U128, U128 )
OPCODE(VectorPairedMaxU16, U128, U128, U128 )
OPCODE(VectorPairedMaxU32, U128, U128, U128 )
OPCODE(VectorPairedMinS8, U128, U128, U128 )
OPCODE(VectorPairedMinS16, U128, U128, U128 )
OPCODE(VectorPairedMinS32, U128, U128, U128 )
OPCODE(VectorPairedMinU8, U128, U128, U128 )
OPCODE(VectorPairedMinU16, U128, U128, U128 )
OPCODE(VectorPairedMinU32, U128, U128, U128 )
OPCODE(VectorPolynomialMultiply8, U128, U128, U128 )
OPCODE(VectorPolynomialMultiplyLong8, U128, U128, U128 )
OPCODE(VectorPolynomialMultiplyLong64, U128, U128, U128 )
OPCODE(VectorPopulationCount, U128, U128 )
OPCODE(VectorReverseBits, U128, U128 )
OPCODE(VectorRoundingHalvingAddS8, U128, U128, U128 )
OPCODE(VectorRoundingHalvingAddS16, U128, U128, U128 )
OPCODE(VectorRoundingHalvingAddS32, U128, U128, U128 )
OPCODE(VectorRoundingHalvingAddU8, U128, U128, U128 )
OPCODE(VectorRoundingHalvingAddU16, U128, U128, U128 )
OPCODE(VectorRoundingHalvingAddU32, U128, U128, U128 )
OPCODE(VectorRoundingShiftLeftS8, U128, U128, U128 )
OPCODE(VectorRoundingShiftLeftS16, U128, U128, U128 )
OPCODE(VectorRoundingShiftLeftS32, U128, U128, U128 )
OPCODE(VectorRoundingShiftLeftS64, U128, U128, U128 )
OPCODE(VectorRoundingShiftLeftU8, U128, U128, U128 )
OPCODE(VectorRoundingShiftLeftU16, U128, U128, U128 )
OPCODE(VectorRoundingShiftLeftU32, U128, U128, U128 )
OPCODE(VectorRoundingShiftLeftU64, U128, U128, U128 )
OPCODE(VectorShuffleHighHalfwords, U128, U128, U8 )
OPCODE(VectorShuffleLowHalfwords, U128, U128, U8 )
OPCODE(VectorShuffleWords, U128, U128, U8 )
OPCODE(VectorSignExtend8, U128, U128 )
OPCODE(VectorSignExtend16, U128, U128 )
OPCODE(VectorSignExtend32, U128, U128 )
OPCODE(VectorSignExtend64, U128, U128 )
OPCODE(VectorSignedAbsoluteDifference8, U128, U128, U128 )
OPCODE(VectorSignedAbsoluteDifference16, U128, U128, U128 )
OPCODE(VectorSignedAbsoluteDifference32, U128, U128, U128 )
OPCODE(VectorSignedMultiply16, Void, U128, U128 )
OPCODE(VectorSignedMultiply32, Void, U128, U128 )
OPCODE(VectorSignedSaturatedAbs8, U128, U128 )
OPCODE(VectorSignedSaturatedAbs16, U128, U128 )
OPCODE(VectorSignedSaturatedAbs32, U128, U128 )
OPCODE(VectorSignedSaturatedAbs64, U128, U128 )
OPCODE(VectorSignedSaturatedAccumulateUnsigned8, U128, U128, U128 )
OPCODE(VectorSignedSaturatedAccumulateUnsigned16, U128, U128, U128 )
OPCODE(VectorSignedSaturatedAccumulateUnsigned32, U128, U128, U128 )
OPCODE(VectorSignedSaturatedAccumulateUnsigned64, U128, U128, U128 )
OPCODE(VectorSignedSaturatedDoublingMultiply16, Void, U128, U128 )
OPCODE(VectorSignedSaturatedDoublingMultiply32, Void, U128, U128 )
OPCODE(VectorSignedSaturatedDoublingMultiplyLong16, U128, U128, U128 )
OPCODE(VectorSignedSaturatedDoublingMultiplyLong32, U128, U128, U128 )
OPCODE(VectorSignedSaturatedNarrowToSigned16, U128, U128 )
OPCODE(VectorSignedSaturatedNarrowToSigned32, U128, U128 )
OPCODE(VectorSignedSaturatedNarrowToSigned64, U128, U128 )
OPCODE(VectorSignedSaturatedNarrowToUnsigned16, U128, U128 )
OPCODE(VectorSignedSaturatedNarrowToUnsigned32, U128, U128 )
OPCODE(VectorSignedSaturatedNarrowToUnsigned64, U128, U128 )
OPCODE(VectorSignedSaturatedNeg8, U128, U128 )
OPCODE(VectorSignedSaturatedNeg16, U128, U128 )
OPCODE(VectorSignedSaturatedNeg32, U128, U128 )
OPCODE(VectorSignedSaturatedNeg64, U128, U128 )
OPCODE(VectorSignedSaturatedShiftLeft8, U128, U128, U128 )
OPCODE(VectorSignedSaturatedShiftLeft16, U128, U128, U128 )
OPCODE(VectorSignedSaturatedShiftLeft32, U128, U128, U128 )
OPCODE(VectorSignedSaturatedShiftLeft64, U128, U128, U128 )
OPCODE(VectorSignedSaturatedShiftLeftUnsigned8, U128, U128, U128 )
OPCODE(VectorSignedSaturatedShiftLeftUnsigned16, U128, U128, U128 )
OPCODE(VectorSignedSaturatedShiftLeftUnsigned32, U128, U128, U128 )
OPCODE(VectorSignedSaturatedShiftLeftUnsigned64, U128, U128, U128 )
OPCODE(VectorSub8, U128, U128, U128 )
OPCODE(VectorSub16, U128, U128, U128 )
OPCODE(VectorSub32, U128, U128, U128 )
OPCODE(VectorSub64, U128, U128, U128 )
OPCODE(VectorTable, Table, Opaque, Opaque, Opaque, Opaque )
OPCODE(VectorTableLookup64, U64, U64, Table, U64 )
OPCODE(VectorTableLookup128, U128, U128, Table, U128 )
OPCODE(VectorTranspose8, U128, U128, U128, U1 )
OPCODE(VectorTranspose16, U128, U128, U128, U1 )
OPCODE(VectorTranspose32, U128, U128, U128, U1 )
OPCODE(VectorTranspose64, U128, U128, U128, U1 )
OPCODE(VectorUnsignedAbsoluteDifference8, U128, U128, U128 )
OPCODE(VectorUnsignedAbsoluteDifference16, U128, U128, U128 )
OPCODE(VectorUnsignedAbsoluteDifference32, U128, U128, U128 )
OPCODE(VectorUnsignedMultiply16, Void, U128, U128 )
OPCODE(VectorUnsignedMultiply32, Void, U128, U128 )
OPCODE(VectorUnsignedRecipEstimate, U128, U128 )
OPCODE(VectorUnsignedRecipSqrtEstimate, U128, U128 )
OPCODE(VectorUnsignedSaturatedAccumulateSigned8, U128, U128, U128 )
OPCODE(VectorUnsignedSaturatedAccumulateSigned16, U128, U128, U128 )
OPCODE(VectorUnsignedSaturatedAccumulateSigned32, U128, U128, U128 )
OPCODE(VectorUnsignedSaturatedAccumulateSigned64, U128, U128, U128 )
OPCODE(VectorUnsignedSaturatedNarrow16, U128, U128 )
OPCODE(VectorUnsignedSaturatedNarrow32, U128, U128 )
OPCODE(VectorUnsignedSaturatedNarrow64, U128, U128 )
OPCODE(VectorUnsignedSaturatedShiftLeft8, U128, U128, U128 )
OPCODE(VectorUnsignedSaturatedShiftLeft16, U128, U128, U128 )
OPCODE(VectorUnsignedSaturatedShiftLeft32, U128, U128, U128 )
OPCODE(VectorUnsignedSaturatedShiftLeft64, U128, U128, U128 )
OPCODE(VectorZeroExtend8, U128, U128 )
OPCODE(VectorZeroExtend16, U128, U128 )
OPCODE(VectorZeroExtend32, U128, U128 )
OPCODE(VectorZeroExtend64, U128, U128 )
OPCODE(VectorZeroUpper, U128, U128 )
OPCODE(ZeroVector, U128, )
// Floating-point operations
OPCODE(FPAbs16, U16, U16 )
OPCODE(FPAbs32, U32, U32 )
OPCODE(FPAbs64, U64, U64 )
OPCODE(FPAdd32, U32, U32, U32 )
OPCODE(FPAdd64, U64, U64, U64 )
OPCODE(FPCompare32, NZCV, U32, U32, U1 )
OPCODE(FPCompare64, NZCV, U64, U64, U1 )
OPCODE(FPDiv32, U32, U32, U32 )
OPCODE(FPDiv64, U64, U64, U64 )
OPCODE(FPMax32, U32, U32, U32 )
OPCODE(FPMax64, U64, U64, U64 )
OPCODE(FPMaxNumeric32, U32, U32, U32 )
OPCODE(FPMaxNumeric64, U64, U64, U64 )
OPCODE(FPMin32, U32, U32, U32 )
OPCODE(FPMin64, U64, U64, U64 )
OPCODE(FPMinNumeric32, U32, U32, U32 )
OPCODE(FPMinNumeric64, U64, U64, U64 )
OPCODE(FPMul32, U32, U32, U32 )
OPCODE(FPMul64, U64, U64, U64 )
OPCODE(FPMulAdd16, U16, U16, U16, U16 )
OPCODE(FPMulAdd32, U32, U32, U32, U32 )
OPCODE(FPMulAdd64, U64, U64, U64, U64 )
OPCODE(FPMulX32, U32, U32, U32 )
OPCODE(FPMulX64, U64, U64, U64 )
OPCODE(FPNeg16, U16, U16 )
OPCODE(FPNeg32, U32, U32 )
OPCODE(FPNeg64, U64, U64 )
OPCODE(FPRecipEstimate16, U16, U16 )
OPCODE(FPRecipEstimate32, U32, U32 )
OPCODE(FPRecipEstimate64, U64, U64 )
OPCODE(FPRecipExponent16, U16, U16 )
OPCODE(FPRecipExponent32, U32, U32 )
OPCODE(FPRecipExponent64, U64, U64 )
OPCODE(FPRecipStepFused16, U16, U16, U16 )
OPCODE(FPRecipStepFused32, U32, U32, U32 )
OPCODE(FPRecipStepFused64, U64, U64, U64 )
OPCODE(FPRoundInt16, U16, U16, U8, U1 )
OPCODE(FPRoundInt32, U32, U32, U8, U1 )
OPCODE(FPRoundInt64, U64, U64, U8, U1 )
OPCODE(FPRSqrtEstimate16, U16, U16 )
OPCODE(FPRSqrtEstimate32, U32, U32 )
OPCODE(FPRSqrtEstimate64, U64, U64 )
OPCODE(FPRSqrtStepFused16, U16, U16, U16 )
OPCODE(FPRSqrtStepFused32, U32, U32, U32 )
OPCODE(FPRSqrtStepFused64, U64, U64, U64 )
OPCODE(FPSqrt32, U32, U32 )
OPCODE(FPSqrt64, U64, U64 )
OPCODE(FPSub32, U32, U32, U32 )
OPCODE(FPSub64, U64, U64, U64 )
// Floating-point conversions
OPCODE(FPHalfToDouble, U64, U16, U8 )
OPCODE(FPHalfToSingle, U32, U16, U8 )
OPCODE(FPSingleToDouble, U64, U32, U8 )
OPCODE(FPSingleToHalf, U16, U32, U8 )
OPCODE(FPDoubleToHalf, U16, U64, U8 )
OPCODE(FPDoubleToSingle, U32, U64, U8 )
OPCODE(FPDoubleToFixedS16, U16, U64, U8, U8 )
OPCODE(FPDoubleToFixedS32, U32, U64, U8, U8 )
OPCODE(FPDoubleToFixedS64, U64, U64, U8, U8 )
OPCODE(FPDoubleToFixedU16, U16, U64, U8, U8 )
OPCODE(FPDoubleToFixedU32, U32, U64, U8, U8 )
OPCODE(FPDoubleToFixedU64, U64, U64, U8, U8 )
OPCODE(FPHalfToFixedS16, U16, U16, U8, U8 )
OPCODE(FPHalfToFixedS32, U32, U16, U8, U8 )
OPCODE(FPHalfToFixedS64, U64, U16, U8, U8 )
OPCODE(FPHalfToFixedU16, U16, U16, U8, U8 )
OPCODE(FPHalfToFixedU32, U32, U16, U8, U8 )
OPCODE(FPHalfToFixedU64, U64, U16, U8, U8 )
OPCODE(FPSingleToFixedS16, U16, U32, U8, U8 )
OPCODE(FPSingleToFixedS32, U32, U32, U8, U8 )
OPCODE(FPSingleToFixedS64, U64, U32, U8, U8 )
OPCODE(FPSingleToFixedU16, U16, U32, U8, U8 )
OPCODE(FPSingleToFixedU32, U32, U32, U8, U8 )
OPCODE(FPSingleToFixedU64, U64, U32, U8, U8 )
OPCODE(FPFixedU16ToSingle, U32, U16, U8, U8 )
OPCODE(FPFixedS16ToSingle, U32, U16, U8, U8 )
OPCODE(FPFixedU16ToDouble, U64, U16, U8, U8 )
OPCODE(FPFixedS16ToDouble, U64, U16, U8, U8 )
OPCODE(FPFixedU32ToSingle, U32, U32, U8, U8 )
OPCODE(FPFixedS32ToSingle, U32, U32, U8, U8 )
OPCODE(FPFixedU32ToDouble, U64, U32, U8, U8 )
OPCODE(FPFixedS32ToDouble, U64, U32, U8, U8 )
OPCODE(FPFixedU64ToDouble, U64, U64, U8, U8 )
OPCODE(FPFixedU64ToSingle, U32, U64, U8, U8 )
OPCODE(FPFixedS64ToDouble, U64, U64, U8, U8 )
OPCODE(FPFixedS64ToSingle, U32, U64, U8, U8 )
// Floating-point vector instructions
OPCODE(FPVectorAbs16, U128, U128 )
OPCODE(FPVectorAbs32, U128, U128 )
OPCODE(FPVectorAbs64, U128, U128 )
OPCODE(FPVectorAdd32, U128, U128, U128, U1 )
OPCODE(FPVectorAdd64, U128, U128, U128, U1 )
OPCODE(FPVectorDiv32, U128, U128, U128, U1 )
OPCODE(FPVectorDiv64, U128, U128, U128, U1 )
OPCODE(FPVectorEqual16, U128, U128, U128, U1 )
OPCODE(FPVectorEqual32, U128, U128, U128, U1 )
OPCODE(FPVectorEqual64, U128, U128, U128, U1 )
OPCODE(FPVectorFromSignedFixed32, U128, U128, U8, U8, U1 )
OPCODE(FPVectorFromSignedFixed64, U128, U128, U8, U8, U1 )
OPCODE(FPVectorFromUnsignedFixed32, U128, U128, U8, U8, U1 )
OPCODE(FPVectorFromUnsignedFixed64, U128, U128, U8, U8, U1 )
OPCODE(FPVectorGreater32, U128, U128, U128, U1 )
OPCODE(FPVectorGreater64, U128, U128, U128, U1 )
OPCODE(FPVectorGreaterEqual32, U128, U128, U128, U1 )
OPCODE(FPVectorGreaterEqual64, U128, U128, U128, U1 )
OPCODE(FPVectorMax32, U128, U128, U128, U1 )
OPCODE(FPVectorMax64, U128, U128, U128, U1 )
OPCODE(FPVectorMin32, U128, U128, U128, U1 )
OPCODE(FPVectorMin64, U128, U128, U128, U1 )
OPCODE(FPVectorMul32, U128, U128, U128, U1 )
OPCODE(FPVectorMul64, U128, U128, U128, U1 )
OPCODE(FPVectorMulAdd16, U128, U128, U128, U128, U1 )
OPCODE(FPVectorMulAdd32, U128, U128, U128, U128, U1 )
OPCODE(FPVectorMulAdd64, U128, U128, U128, U128, U1 )
OPCODE(FPVectorMulX32, U128, U128, U128, U1 )
OPCODE(FPVectorMulX64, U128, U128, U128, U1 )
OPCODE(FPVectorNeg16, U128, U128 )
OPCODE(FPVectorNeg32, U128, U128 )
OPCODE(FPVectorNeg64, U128, U128 )
OPCODE(FPVectorPairedAdd32, U128, U128, U128, U1 )
OPCODE(FPVectorPairedAdd64, U128, U128, U128, U1 )
OPCODE(FPVectorPairedAddLower32, U128, U128, U128, U1 )
OPCODE(FPVectorPairedAddLower64, U128, U128, U128, U1 )
OPCODE(FPVectorRecipEstimate16, U128, U128, U1 )
OPCODE(FPVectorRecipEstimate32, U128, U128, U1 )
OPCODE(FPVectorRecipEstimate64, U128, U128, U1 )
OPCODE(FPVectorRecipStepFused16, U128, U128, U128, U1 )
OPCODE(FPVectorRecipStepFused32, U128, U128, U128, U1 )
OPCODE(FPVectorRecipStepFused64, U128, U128, U128, U1 )
OPCODE(FPVectorRoundInt16, U128, U128, U8, U1, U1 )
OPCODE(FPVectorRoundInt32, U128, U128, U8, U1, U1 )
OPCODE(FPVectorRoundInt64, U128, U128, U8, U1, U1 )
OPCODE(FPVectorRSqrtEstimate16, U128, U128, U1 )
OPCODE(FPVectorRSqrtEstimate32, U128, U128, U1 )
OPCODE(FPVectorRSqrtEstimate64, U128, U128, U1 )
OPCODE(FPVectorRSqrtStepFused16, U128, U128, U128, U1 )
OPCODE(FPVectorRSqrtStepFused32, U128, U128, U128, U1 )
OPCODE(FPVectorRSqrtStepFused64, U128, U128, U128, U1 )
OPCODE(FPVectorSqrt32, U128, U128, U1 )
OPCODE(FPVectorSqrt64, U128, U128, U1 )
OPCODE(FPVectorSub32, U128, U128, U128, U1 )
OPCODE(FPVectorSub64, U128, U128, U128, U1 )
OPCODE(FPVectorToSignedFixed16, U128, U128, U8, U8, U1 )
OPCODE(FPVectorToSignedFixed32, U128, U128, U8, U8, U1 )
OPCODE(FPVectorToSignedFixed64, U128, U128, U8, U8, U1 )
OPCODE(FPVectorToUnsignedFixed16, U128, U128, U8, U8, U1 )
OPCODE(FPVectorToUnsignedFixed32, U128, U128, U8, U8, U1 )
OPCODE(FPVectorToUnsignedFixed64, U128, U128, U8, U8, U1 )
// A32 Memory access
A32OPC(ClearExclusive, Void, )
A32OPC(ReadMemory8, U8, U32 )
A32OPC(ReadMemory16, U16, U32 )
A32OPC(ReadMemory32, U32, U32 )
A32OPC(ReadMemory64, U64, U32 )
A32OPC(ExclusiveReadMemory8, U8, U32 )
A32OPC(ExclusiveReadMemory16, U16, U32 )
A32OPC(ExclusiveReadMemory32, U32, U32 )
A32OPC(ExclusiveReadMemory64, U64, U32 )
A32OPC(WriteMemory8, Void, U32, U8 )
A32OPC(WriteMemory16, Void, U32, U16 )
A32OPC(WriteMemory32, Void, U32, U32 )
A32OPC(WriteMemory64, Void, U32, U64 )
A32OPC(ExclusiveWriteMemory8, U32, U32, U8 )
A32OPC(ExclusiveWriteMemory16, U32, U32, U16 )
A32OPC(ExclusiveWriteMemory32, U32, U32, U32 )
A32OPC(ExclusiveWriteMemory64, U32, U32, U64 )
// A64 Memory access
A64OPC(ClearExclusive, Void, )
A64OPC(ReadMemory8, U8, U64 )
A64OPC(ReadMemory16, U16, U64 )
A64OPC(ReadMemory32, U32, U64 )
A64OPC(ReadMemory64, U64, U64 )
A64OPC(ReadMemory128, U128, U64 )
A64OPC(ExclusiveReadMemory8, U8, U64 )
A64OPC(ExclusiveReadMemory16, U16, U64 )
A64OPC(ExclusiveReadMemory32, U32, U64 )
A64OPC(ExclusiveReadMemory64, U64, U64 )
A64OPC(ExclusiveReadMemory128, U128, U64 )
A64OPC(WriteMemory8, Void, U64, U8 )
A64OPC(WriteMemory16, Void, U64, U16 )
A64OPC(WriteMemory32, Void, U64, U32 )
A64OPC(WriteMemory64, Void, U64, U64 )
A64OPC(WriteMemory128, Void, U64, U128 )
A64OPC(ExclusiveWriteMemory8, U32, U64, U8 )
A64OPC(ExclusiveWriteMemory16, U32, U64, U16 )
A64OPC(ExclusiveWriteMemory32, U32, U64, U32 )
A64OPC(ExclusiveWriteMemory64, U32, U64, U64 )
A64OPC(ExclusiveWriteMemory128, U32, U64, U128 )
// Coprocessor
A32OPC(CoprocInternalOperation, Void, CoprocInfo )
A32OPC(CoprocSendOneWord, Void, CoprocInfo, U32 )
A32OPC(CoprocSendTwoWords, Void, CoprocInfo, U32, U32 )
A32OPC(CoprocGetOneWord, U32, CoprocInfo )
A32OPC(CoprocGetTwoWords, U64, CoprocInfo )
A32OPC(CoprocLoadWords, Void, CoprocInfo, U32 )
A32OPC(CoprocStoreWords, Void, CoprocInfo, U32 )

126
externals/dynarmic/src/frontend/ir/terminal.h vendored Executable file
View File

@@ -0,0 +1,126 @@
/* This file is part of the dynarmic project.
* Copyright (c) 2016 MerryMage
* SPDX-License-Identifier: 0BSD
*/
#pragma once
#include <boost/variant.hpp>
#include "common/common_types.h"
#include "frontend/ir/cond.h"
#include "frontend/ir/location_descriptor.h"
namespace Dynarmic::IR {
namespace Term {
struct Invalid {};
/**
* This terminal instruction calls the interpreter, starting at `next`.
* The interpreter must interpret exactly `num_instructions` instructions.
*/
struct Interpret {
explicit Interpret(const LocationDescriptor& next_) : next(next_) {}
LocationDescriptor next; ///< Location at which interpretation starts.
size_t num_instructions = 1;
};
/**
* This terminal instruction returns control to the dispatcher.
* The dispatcher will use the current cpu state to determine what comes next.
*/
struct ReturnToDispatch {};
/**
* This terminal instruction jumps to the basic block described by `next` if we have enough
* cycles remaining. If we do not have enough cycles remaining, we return to the
* dispatcher, which will return control to the host.
*/
struct LinkBlock {
explicit LinkBlock(const LocationDescriptor& next_) : next(next_) {}
LocationDescriptor next; ///< Location descriptor for next block.
};
/**
* This terminal instruction jumps to the basic block described by `next` unconditionally.
* This is an optimization and MUST only be emitted when this is guaranteed not to result
* in hanging, even in the face of other optimizations. (In practice, this means that only
* forward jumps to short-ish blocks would use this instruction.)
* A backend that doesn't support this optimization may choose to implement this exactly
* as LinkBlock.
*/
struct LinkBlockFast {
explicit LinkBlockFast(const LocationDescriptor& next_) : next(next_) {}
LocationDescriptor next; ///< Location descriptor for next block.
};
/**
* This terminal instruction checks the top of the Return Stack Buffer against the current
* location descriptor. If RSB lookup fails, control is returned to the dispatcher.
* This is an optimization for faster function calls. A backend that doesn't support
* this optimization or doesn't have a RSB may choose to implement this exactly as
* ReturnToDispatch.
*/
struct PopRSBHint {};
/**
* This terminal instruction performs a lookup of the current location descriptor in the
* fast dispatch lookup table. A backend that doesn't support this optimization may choose
* to implement this exactly as ReturnToDispatch.
*/
struct FastDispatchHint {};
struct If;
struct CheckBit;
struct CheckHalt;
/// A Terminal is the terminal instruction in a MicroBlock.
using Terminal = boost::variant<
Invalid,
Interpret,
ReturnToDispatch,
LinkBlock,
LinkBlockFast,
PopRSBHint,
FastDispatchHint,
boost::recursive_wrapper<If>,
boost::recursive_wrapper<CheckBit>,
boost::recursive_wrapper<CheckHalt>
>;
/**
* This terminal instruction conditionally executes one terminal or another depending
* on the run-time state of the ARM flags.
*/
struct If {
If(Cond if_, Terminal then_, Terminal else_) : if_(if_), then_(std::move(then_)), else_(std::move(else_)) {}
Cond if_;
Terminal then_;
Terminal else_;
};
/**
* This terminal instruction conditionally executes one terminal or another depending
* on the run-time state of the check bit.
* then_ is executed if the check bit is non-zero, otherwise else_ is executed.
*/
struct CheckBit {
CheckBit(Terminal then_, Terminal else_) : then_(std::move(then_)), else_(std::move(else_)) {}
Terminal then_;
Terminal else_;
};
/**
* This terminal instruction checks if a halt was requested. If it wasn't, else_ is
* executed.
*/
struct CheckHalt {
explicit CheckHalt(Terminal else_) : else_(std::move(else_)) {}
Terminal else_;
};
} // namespace Term
using Term::Terminal;
} // namespace Dynarmic::IR

51
externals/dynarmic/src/frontend/ir/type.cpp vendored Executable file
View File

@@ -0,0 +1,51 @@
/* This file is part of the dynarmic project.
* Copyright (c) 2016 MerryMage
* SPDX-License-Identifier: 0BSD
*/
#include <array>
#include <ostream>
#include <string>
#include "frontend/ir/type.h"
namespace Dynarmic::IR {
std::string GetNameOf(Type type) {
static constexpr std::array names{
"A32Reg", "A32ExtReg",
"A64Reg", "A64Vec",
"Opaque",
"U1", "U8", "U16", "U32", "U64", "U128",
"CoprocInfo",
"NZCVFlags",
"Cond",
"Table"
};
const size_t bits = static_cast<size_t>(type);
if (bits == 0) {
return "Void";
}
std::string result;
for (size_t i = 0; i < names.size(); i++) {
if ((bits & (size_t(1) << i)) != 0) {
if (!result.empty()) {
result += '|';
}
result += names[i];
}
}
return result;
}
bool AreTypesCompatible(Type t1, Type t2) {
return t1 == t2 || t1 == Type::Opaque || t2 == Type::Opaque;
}
std::ostream& operator<<(std::ostream& o, Type type) {
return o << GetNameOf(type);
}
} // namespace Dynarmic::IR

53
externals/dynarmic/src/frontend/ir/type.h vendored Executable file
View File

@@ -0,0 +1,53 @@
/* This file is part of the dynarmic project.
* Copyright (c) 2016 MerryMage
* SPDX-License-Identifier: 0BSD
*/
#pragma once
#include <iosfwd>
#include <string>
#include "common/common_types.h"
namespace Dynarmic::IR {
/**
* The intermediate representation is typed. These are the used by our IR.
*/
enum class Type {
Void = 0,
A32Reg = 1 << 0,
A32ExtReg = 1 << 1,
A64Reg = 1 << 2,
A64Vec = 1 << 3,
Opaque = 1 << 4,
U1 = 1 << 5,
U8 = 1 << 6,
U16 = 1 << 7,
U32 = 1 << 8,
U64 = 1 << 9,
U128 = 1 << 10,
CoprocInfo = 1 << 11,
NZCVFlags = 1 << 12,
Cond = 1 << 13,
Table = 1 << 14,
};
constexpr Type operator|(Type a, Type b) {
return static_cast<Type>(static_cast<size_t>(a) | static_cast<size_t>(b));
}
constexpr Type operator&(Type a, Type b) {
return static_cast<Type>(static_cast<size_t>(a) & static_cast<size_t>(b));
}
/// Get the name of a type.
std::string GetNameOf(Type type);
/// @returns true if t1 and t2 are compatible types
bool AreTypesCompatible(Type t1, Type t2);
std::ostream& operator<<(std::ostream& o, Type type);
} // namespace Dynarmic::IR

222
externals/dynarmic/src/frontend/ir/value.cpp vendored Executable file
View File

@@ -0,0 +1,222 @@
/* This file is part of the dynarmic project.
* Copyright (c) 2016 MerryMage
* SPDX-License-Identifier: 0BSD
*/
#include "common/assert.h"
#include "common/bit_util.h"
#include "frontend/ir/microinstruction.h"
#include "frontend/ir/opcodes.h"
#include "frontend/ir/type.h"
#include "frontend/ir/value.h"
namespace Dynarmic::IR {
Value::Value(Inst* value) : type(Type::Opaque) {
inner.inst = value;
}
Value::Value(A32::Reg value) : type(Type::A32Reg) {
inner.imm_a32regref = value;
}
Value::Value(A32::ExtReg value) : type(Type::A32ExtReg) {
inner.imm_a32extregref = value;
}
Value::Value(A64::Reg value) : type(Type::A64Reg) {
inner.imm_a64regref = value;
}
Value::Value(A64::Vec value) : type(Type::A64Vec) {
inner.imm_a64vecref = value;
}
Value::Value(bool value) : type(Type::U1) {
inner.imm_u1 = value;
}
Value::Value(u8 value) : type(Type::U8) {
inner.imm_u8 = value;
}
Value::Value(u16 value) : type(Type::U16) {
inner.imm_u16 = value;
}
Value::Value(u32 value) : type(Type::U32) {
inner.imm_u32 = value;
}
Value::Value(u64 value) : type(Type::U64) {
inner.imm_u64 = value;
}
Value::Value(CoprocessorInfo value) : type(Type::CoprocInfo) {
inner.imm_coproc = value;
}
Value::Value(Cond value) : type(Type::Cond) {
inner.imm_cond = value;
}
bool Value::IsIdentity() const {
if (type == Type::Opaque)
return inner.inst->GetOpcode() == Opcode::Identity;
return false;
}
bool Value::IsImmediate() const {
if (IsIdentity())
return inner.inst->GetArg(0).IsImmediate();
return type != Type::Opaque;
}
bool Value::IsEmpty() const {
return type == Type::Void;
}
Type Value::GetType() const {
if (IsIdentity())
return inner.inst->GetArg(0).GetType();
if (type == Type::Opaque)
return inner.inst->GetType();
return type;
}
A32::Reg Value::GetA32RegRef() const {
ASSERT(type == Type::A32Reg);
return inner.imm_a32regref;
}
A32::ExtReg Value::GetA32ExtRegRef() const {
ASSERT(type == Type::A32ExtReg);
return inner.imm_a32extregref;
}
A64::Reg Value::GetA64RegRef() const {
ASSERT(type == Type::A64Reg);
return inner.imm_a64regref;
}
A64::Vec Value::GetA64VecRef() const {
ASSERT(type == Type::A64Vec);
return inner.imm_a64vecref;
}
Inst* Value::GetInst() const {
ASSERT(type == Type::Opaque);
return inner.inst;
}
Inst* Value::GetInstRecursive() const {
ASSERT(type == Type::Opaque);
if (IsIdentity())
return inner.inst->GetArg(0).GetInstRecursive();
return inner.inst;
}
bool Value::GetU1() const {
if (IsIdentity())
return inner.inst->GetArg(0).GetU1();
ASSERT(type == Type::U1);
return inner.imm_u1;
}
u8 Value::GetU8() const {
if (IsIdentity())
return inner.inst->GetArg(0).GetU8();
ASSERT(type == Type::U8);
return inner.imm_u8;
}
u16 Value::GetU16() const {
if (IsIdentity())
return inner.inst->GetArg(0).GetU16();
ASSERT(type == Type::U16);
return inner.imm_u16;
}
u32 Value::GetU32() const {
if (IsIdentity())
return inner.inst->GetArg(0).GetU32();
ASSERT(type == Type::U32);
return inner.imm_u32;
}
u64 Value::GetU64() const {
if (IsIdentity())
return inner.inst->GetArg(0).GetU64();
ASSERT(type == Type::U64);
return inner.imm_u64;
}
Value::CoprocessorInfo Value::GetCoprocInfo() const {
if (IsIdentity())
return inner.inst->GetArg(0).GetCoprocInfo();
ASSERT(type == Type::CoprocInfo);
return inner.imm_coproc;
}
Cond Value::GetCond() const {
if (IsIdentity())
return inner.inst->GetArg(0).GetCond();
ASSERT(type == Type::Cond);
return inner.imm_cond;
}
s64 Value::GetImmediateAsS64() const {
ASSERT(IsImmediate());
switch (GetType()) {
case IR::Type::U1:
return s64(GetU1());
case IR::Type::U8:
return s64(Common::SignExtend<8, u64>(GetU8()));
case IR::Type::U16:
return s64(Common::SignExtend<16, u64>(GetU16()));
case IR::Type::U32:
return s64(Common::SignExtend<32, u64>(GetU32()));
case IR::Type::U64:
return s64(GetU64());
default:
ASSERT_FALSE("GetImmediateAsS64 called on an incompatible Value type.");
}
}
u64 Value::GetImmediateAsU64() const {
ASSERT(IsImmediate());
switch (GetType()) {
case IR::Type::U1:
return u64(GetU1());
case IR::Type::U8:
return u64(GetU8());
case IR::Type::U16:
return u64(GetU16());
case IR::Type::U32:
return u64(GetU32());
case IR::Type::U64:
return u64(GetU64());
default:
ASSERT_FALSE("GetImmediateAsU64 called on an incompatible Value type.");
}
}
bool Value::IsSignedImmediate(s64 value) const {
return IsImmediate() && GetImmediateAsS64() == value;
}
bool Value::IsUnsignedImmediate(u64 value) const {
return IsImmediate() && GetImmediateAsU64() == value;
}
bool Value::HasAllBitsSet() const {
return IsSignedImmediate(-1);
}
bool Value::IsZero() const {
return IsUnsignedImmediate(0);
}
} // namespace Dynarmic::IR

175
externals/dynarmic/src/frontend/ir/value.h vendored Executable file
View File

@@ -0,0 +1,175 @@
/* This file is part of the dynarmic project.
* Copyright (c) 2016 MerryMage
* SPDX-License-Identifier: 0BSD
*/
#pragma once
#include <type_traits>
#include "common/assert.h"
#include "common/common_types.h"
#include "frontend/ir/type.h"
namespace Dynarmic::A32 {
enum class ExtReg;
enum class Reg;
}
namespace Dynarmic::A64 {
enum class Reg;
enum class Vec;
}
namespace Dynarmic::IR {
class Inst;
enum class Cond;
/**
* A representation of a value in the IR.
* A value may either be an immediate or the result of a microinstruction.
*/
class Value {
public:
using CoprocessorInfo = std::array<u8, 8>;
Value() : type(Type::Void) {}
explicit Value(Inst* value);
explicit Value(A32::Reg value);
explicit Value(A32::ExtReg value);
explicit Value(A64::Reg value);
explicit Value(A64::Vec value);
explicit Value(bool value);
explicit Value(u8 value);
explicit Value(u16 value);
explicit Value(u32 value);
explicit Value(u64 value);
explicit Value(CoprocessorInfo value);
explicit Value(Cond value);
bool IsIdentity() const;
bool IsEmpty() const;
bool IsImmediate() const;
Type GetType() const;
Inst* GetInst() const;
Inst* GetInstRecursive() const;
A32::Reg GetA32RegRef() const;
A32::ExtReg GetA32ExtRegRef() const;
A64::Reg GetA64RegRef() const;
A64::Vec GetA64VecRef() const;
bool GetU1() const;
u8 GetU8() const;
u16 GetU16() const;
u32 GetU32() const;
u64 GetU64() const;
CoprocessorInfo GetCoprocInfo() const;
Cond GetCond() const;
/**
* Retrieves the immediate of a Value instance as a signed 64-bit value.
*
* @pre The value contains either a U1, U8, U16, U32, or U64 value.
* Breaking this precondition will cause an assertion to be invoked.
*/
s64 GetImmediateAsS64() const;
/**
* Retrieves the immediate of a Value instance as an unsigned 64-bit value.
*
* @pre The value contains either a U1, U8, U16, U32, or U64 value.
* Breaking this precondition will cause an assertion to be invoked.
*/
u64 GetImmediateAsU64() const;
/**
* Determines whether or not the contained value matches the provided signed one.
*
* Note that this function will always return false if the contained
* value is not a a constant value. In other words, if IsImmediate()
* would return false on an instance, then so will this function.
*
* @param value The value to check against the contained value.
*/
bool IsSignedImmediate(s64 value) const;
/**
* Determines whether or not the contained value matches the provided unsigned one.
*
* Note that this function will always return false if the contained
* value is not a a constant value. In other words, if IsImmediate()
* would return false on an instance, then so will this function.
*
* @param value The value to check against the contained value.
*/
bool IsUnsignedImmediate(u64 value) const;
/**
* Determines whether or not the contained constant value has all bits set.
*
* @pre The value contains either a U1, U8, U16, U32, or U64 value.
* Breaking this precondition will cause an assertion to be invoked.
*/
bool HasAllBitsSet() const;
/**
* Whether or not the current value contains a representation of zero.
*
* Note that this function will always return false if the contained
* value is not a a constant value. In other words, if IsImmediate()
* would return false on an instance, then so will this function.
*/
bool IsZero() const;
private:
Type type;
union {
Inst* inst; // type == Type::Opaque
A32::Reg imm_a32regref;
A32::ExtReg imm_a32extregref;
A64::Reg imm_a64regref;
A64::Vec imm_a64vecref;
bool imm_u1;
u8 imm_u8;
u16 imm_u16;
u32 imm_u32;
u64 imm_u64;
CoprocessorInfo imm_coproc;
Cond imm_cond;
} inner;
};
static_assert(sizeof(Value) <= 2 * sizeof(u64), "IR::Value should be kept small in size");
template <Type type_>
class TypedValue final : public Value {
public:
TypedValue() = default;
template <Type other_type, typename = std::enable_if_t<(other_type & type_) != Type::Void>>
/* implicit */ TypedValue(const TypedValue<other_type>& value) : Value(value) {
ASSERT((value.GetType() & type_) != Type::Void);
}
explicit TypedValue(const Value& value) : Value(value) {
ASSERT((value.GetType() & type_) != Type::Void);
}
explicit TypedValue(Inst* inst) : TypedValue(Value(inst)) {}
};
using U1 = TypedValue<Type::U1>;
using U8 = TypedValue<Type::U8>;
using U16 = TypedValue<Type::U16>;
using U32 = TypedValue<Type::U32>;
using U64 = TypedValue<Type::U64>;
using U128 = TypedValue<Type::U128>;
using U32U64 = TypedValue<Type::U32 | Type::U64>;
using U16U32U64 = TypedValue<Type::U16 | Type::U32 | Type::U64>;
using UAny = TypedValue<Type::U8 | Type::U16 | Type::U32 | Type::U64>;
using UAnyU128 = TypedValue<Type::U8 | Type::U16 | Type::U32 | Type::U64 | Type::U128>;
using NZCV = TypedValue<Type::NZCVFlags>;
using Table = TypedValue<Type::Table>;
} // namespace Dynarmic::IR