early-access version 1255
This commit is contained in:
245
externals/dynarmic/src/frontend/ir/basic_block.cpp
vendored
Executable file
245
externals/dynarmic/src/frontend/ir/basic_block.cpp
vendored
Executable 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
|
167
externals/dynarmic/src/frontend/ir/basic_block.h
vendored
Executable file
167
externals/dynarmic/src/frontend/ir/basic_block.h
vendored
Executable 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
15
externals/dynarmic/src/frontend/ir/cond.h
vendored
Executable 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
|
2658
externals/dynarmic/src/frontend/ir/ir_emitter.cpp
vendored
Executable file
2658
externals/dynarmic/src/frontend/ir/ir_emitter.cpp
vendored
Executable file
File diff suppressed because it is too large
Load Diff
402
externals/dynarmic/src/frontend/ir/ir_emitter.h
vendored
Executable file
402
externals/dynarmic/src/frontend/ir/ir_emitter.h
vendored
Executable 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
|
18
externals/dynarmic/src/frontend/ir/location_descriptor.cpp
vendored
Executable file
18
externals/dynarmic/src/frontend/ir/location_descriptor.cpp
vendored
Executable 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
|
54
externals/dynarmic/src/frontend/ir/location_descriptor.h
vendored
Executable file
54
externals/dynarmic/src/frontend/ir/location_descriptor.h
vendored
Executable 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
|
732
externals/dynarmic/src/frontend/ir/microinstruction.cpp
vendored
Executable file
732
externals/dynarmic/src/frontend/ir/microinstruction.cpp
vendored
Executable 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
|
164
externals/dynarmic/src/frontend/ir/microinstruction.h
vendored
Executable file
164
externals/dynarmic/src/frontend/ir/microinstruction.h
vendored
Executable 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
|
78
externals/dynarmic/src/frontend/ir/opcodes.cpp
vendored
Executable file
78
externals/dynarmic/src/frontend/ir/opcodes.cpp
vendored
Executable 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
48
externals/dynarmic/src/frontend/ir/opcodes.h
vendored
Executable 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
714
externals/dynarmic/src/frontend/ir/opcodes.inc
vendored
Executable 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
126
externals/dynarmic/src/frontend/ir/terminal.h
vendored
Executable 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
51
externals/dynarmic/src/frontend/ir/type.cpp
vendored
Executable 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
53
externals/dynarmic/src/frontend/ir/type.h
vendored
Executable 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
222
externals/dynarmic/src/frontend/ir/value.cpp
vendored
Executable 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
175
externals/dynarmic/src/frontend/ir/value.h
vendored
Executable 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
|
Reference in New Issue
Block a user