mirror of
https://git.eden-emu.dev/eden-emu/dynarmic
synced 2026-02-04 02:41:21 +01:00
more aggressive inline, motivate 2MB pages (implicit malloc for now)
This commit is contained in:
@@ -9,36 +9,5 @@
|
||||
|
||||
namespace Dynarmic::Common {
|
||||
|
||||
Pool::Pool(size_t object_size, size_t initial_pool_size)
|
||||
: object_size(object_size), slab_size(initial_pool_size) {
|
||||
AllocateNewSlab();
|
||||
}
|
||||
|
||||
Pool::~Pool() {
|
||||
std::free(current_slab);
|
||||
|
||||
for (char* slab : slabs) {
|
||||
std::free(slab);
|
||||
}
|
||||
}
|
||||
|
||||
void* Pool::Alloc() {
|
||||
if (remaining == 0) {
|
||||
slabs.push_back(current_slab);
|
||||
AllocateNewSlab();
|
||||
}
|
||||
|
||||
void* ret = static_cast<void*>(current_ptr);
|
||||
current_ptr += object_size;
|
||||
remaining--;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Pool::AllocateNewSlab() {
|
||||
current_slab = static_cast<char*>(std::malloc(object_size * slab_size));
|
||||
current_ptr = current_slab;
|
||||
remaining = slab_size;
|
||||
}
|
||||
|
||||
} // namespace Dynarmic::Common
|
||||
|
||||
@@ -10,14 +10,20 @@
|
||||
|
||||
namespace Dynarmic::Common {
|
||||
|
||||
/// @tparam object_size Byte-size of objects to construct
|
||||
/// @tparam slab_size Number of objects to have per slab
|
||||
template<size_t object_size, size_t slab_size>
|
||||
class Pool {
|
||||
public:
|
||||
/**
|
||||
* @param object_size Byte-size of objects to construct
|
||||
* @param initial_pool_size Number of objects to have per slab
|
||||
*/
|
||||
Pool(size_t object_size, size_t initial_pool_size);
|
||||
~Pool();
|
||||
inline Pool() noexcept {
|
||||
AllocateNewSlab();
|
||||
}
|
||||
inline ~Pool() noexcept {
|
||||
std::free(current_slab);
|
||||
for (char* slab : slabs) {
|
||||
std::free(slab);
|
||||
}
|
||||
}
|
||||
|
||||
Pool(const Pool&) = delete;
|
||||
Pool(Pool&&) = delete;
|
||||
@@ -25,21 +31,31 @@ public:
|
||||
Pool& operator=(const Pool&) = delete;
|
||||
Pool& operator=(Pool&&) = delete;
|
||||
|
||||
/// Returns a pointer to an `object_size`-bytes block of memory.
|
||||
void* Alloc();
|
||||
|
||||
/// @brief Returns a pointer to an `object_size`-bytes block of memory.
|
||||
[[nodiscard]] void* Alloc() noexcept {
|
||||
if (remaining == 0) {
|
||||
slabs.push_back(current_slab);
|
||||
AllocateNewSlab();
|
||||
}
|
||||
void* ret = static_cast<void*>(current_ptr);
|
||||
current_ptr += object_size;
|
||||
remaining--;
|
||||
return ret;
|
||||
}
|
||||
private:
|
||||
// Allocates a completely new memory slab.
|
||||
// Used when an entirely new slab is needed
|
||||
// due the current one running out of usable space.
|
||||
void AllocateNewSlab();
|
||||
/// @brief Allocates a completely new memory slab.
|
||||
/// Used when an entirely new slab is needed
|
||||
/// due the current one running out of usable space.
|
||||
void AllocateNewSlab() noexcept {
|
||||
current_slab = static_cast<char*>(std::malloc(object_size * slab_size));
|
||||
current_ptr = current_slab;
|
||||
remaining = slab_size;
|
||||
}
|
||||
|
||||
size_t object_size;
|
||||
size_t slab_size;
|
||||
char* current_slab;
|
||||
char* current_ptr;
|
||||
size_t remaining;
|
||||
std::vector<char*> slabs;
|
||||
char* current_slab = nullptr;
|
||||
char* current_ptr = nullptr;
|
||||
size_t remaining = 0;
|
||||
};
|
||||
|
||||
} // namespace Dynarmic::Common
|
||||
|
||||
@@ -22,105 +22,31 @@
|
||||
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)} {}
|
||||
: location{location},
|
||||
end_location{location},
|
||||
cond{Cond::AL},
|
||||
instruction_alloc_pool{std::make_unique<std::remove_reference_t<decltype(*instruction_alloc_pool)>>()}
|
||||
{
|
||||
|
||||
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) {
|
||||
/// 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.
|
||||
Block::iterator Block::PrependNewInst(iterator insertion_point, Opcode opcode, std::initializer_list<Value> args) noexcept {
|
||||
IR::Inst* inst = new (instruction_alloc_pool->Alloc()) IR::Inst(opcode);
|
||||
ASSERT(args.size() == inst->NumArgs());
|
||||
|
||||
DEBUG_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) {
|
||||
static std::string TerminalToString(const Terminal& terminal_variant) noexcept {
|
||||
struct : boost::static_visitor<std::string> {
|
||||
std::string operator()(const Term::Invalid&) const {
|
||||
return "<invalid terminal>";
|
||||
@@ -153,11 +79,10 @@ static std::string TerminalToString(const Terminal& terminal_variant) {
|
||||
return fmt::format("CheckHalt{{{}}}", TerminalToString(terminal.else_));
|
||||
}
|
||||
} visitor;
|
||||
|
||||
return boost::apply_visitor(visitor, terminal_variant);
|
||||
}
|
||||
|
||||
std::string DumpBlock(const IR::Block& block) {
|
||||
std::string DumpBlock(const IR::Block& block) noexcept {
|
||||
std::string ret;
|
||||
|
||||
ret += fmt::format("Block: location={}\n", block.Location());
|
||||
|
||||
@@ -17,39 +17,34 @@
|
||||
#include "dynarmic/ir/microinstruction.h"
|
||||
#include "dynarmic/ir/terminal.h"
|
||||
#include "dynarmic/ir/value.h"
|
||||
|
||||
namespace Dynarmic::Common {
|
||||
class Pool;
|
||||
}
|
||||
#include "dynarmic/ir/dense_list.h"
|
||||
#include "dynarmic/common/memory_pool.h"
|
||||
|
||||
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.
|
||||
*/
|
||||
/// 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 = mcl::intrusive_list<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;
|
||||
//using instruction_list_type = dense_list<Inst>;
|
||||
using instruction_list_type = mcl::intrusive_list<Inst>;
|
||||
using size_type = instruction_list_type::size_type;
|
||||
using iterator = instruction_list_type::iterator;
|
||||
using const_iterator = instruction_list_type::const_iterator;
|
||||
using reverse_iterator = instruction_list_type::reverse_iterator;
|
||||
using const_reverse_iterator = instruction_list_type::const_reverse_iterator;
|
||||
|
||||
explicit Block(const LocationDescriptor& location);
|
||||
~Block();
|
||||
|
||||
~Block() = default;
|
||||
Block(const Block&) = delete;
|
||||
Block& operator=(const Block&) = delete;
|
||||
|
||||
Block(Block&&);
|
||||
Block& operator=(Block&&);
|
||||
Block(Block&&) = default;
|
||||
Block& operator=(Block&&) = default;
|
||||
|
||||
bool empty() const { return instructions.empty(); }
|
||||
size_type size() const { return instructions.size(); }
|
||||
@@ -76,93 +71,117 @@ public:
|
||||
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;
|
||||
/// 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.
|
||||
inline void AppendNewInst(const Opcode opcode, const std::initializer_list<IR::Value> args) noexcept {
|
||||
PrependNewInst(end(), opcode, args);
|
||||
}
|
||||
iterator PrependNewInst(iterator insertion_point, Opcode op, std::initializer_list<Value> args) noexcept;
|
||||
|
||||
/// Gets a mutable reference to the instruction list for this basic block.
|
||||
InstructionList& Instructions();
|
||||
inline instruction_list_type& Instructions() noexcept {
|
||||
return instructions;
|
||||
}
|
||||
/// Gets an immutable reference to the instruction list for this basic block.
|
||||
const InstructionList& Instructions() const;
|
||||
inline const instruction_list_type& Instructions() const noexcept {
|
||||
return instructions;
|
||||
}
|
||||
|
||||
/// Gets the starting location for this basic block.
|
||||
inline LocationDescriptor Location() const noexcept {
|
||||
return location;
|
||||
}
|
||||
/// Gets the end location for this basic block.
|
||||
inline LocationDescriptor EndLocation() const noexcept {
|
||||
return end_location;
|
||||
}
|
||||
/// Sets the end location for this basic block.
|
||||
inline void SetEndLocation(const LocationDescriptor& descriptor) noexcept {
|
||||
end_location = descriptor;
|
||||
}
|
||||
|
||||
/// Gets the condition required to pass in order to execute this block.
|
||||
inline Cond GetCondition() const noexcept {
|
||||
return cond;
|
||||
}
|
||||
/// Sets the condition required to pass in order to execute this block.
|
||||
inline void SetCondition(Cond condition) noexcept {
|
||||
cond = condition;
|
||||
}
|
||||
|
||||
/// Gets the location of the block to execute if the predicated condition fails.
|
||||
inline LocationDescriptor ConditionFailedLocation() const noexcept {
|
||||
return *cond_failed;
|
||||
}
|
||||
/// Sets the location of the block to execute if the predicated condition fails.
|
||||
inline void SetConditionFailedLocation(LocationDescriptor fail_location) noexcept {
|
||||
cond_failed = fail_location;
|
||||
}
|
||||
/// Determines whether or not a predicated condition failure block is present.
|
||||
inline bool HasConditionFailedLocation() const noexcept {
|
||||
return cond_failed.has_value();
|
||||
}
|
||||
|
||||
/// Gets a mutable reference to the condition failed cycle count.
|
||||
inline size_t& ConditionFailedCycleCount() noexcept {
|
||||
return cond_failed_cycle_count;
|
||||
}
|
||||
/// Gets an immutable reference to the condition failed cycle count.
|
||||
inline const size_t& ConditionFailedCycleCount() const noexcept {
|
||||
return cond_failed_cycle_count;
|
||||
}
|
||||
|
||||
/// Gets the terminal instruction for this basic block.
|
||||
Terminal GetTerminal() const;
|
||||
inline Terminal GetTerminal() const noexcept {
|
||||
return terminal;
|
||||
}
|
||||
/// Sets the terminal instruction for this basic block.
|
||||
void SetTerminal(Terminal term);
|
||||
inline void SetTerminal(Terminal term) noexcept {
|
||||
ASSERT_MSG(!HasTerminal(), "Terminal has already been set.");
|
||||
terminal = std::move(term);
|
||||
}
|
||||
/// Replaces the terminal instruction for this basic block.
|
||||
void ReplaceTerminal(Terminal term);
|
||||
inline void ReplaceTerminal(Terminal term) noexcept {
|
||||
ASSERT_MSG(HasTerminal(), "Terminal has not been set.");
|
||||
terminal = std::move(term);
|
||||
}
|
||||
/// Determines whether or not this basic block has a terminal instruction.
|
||||
bool HasTerminal() const;
|
||||
|
||||
inline bool HasTerminal() const noexcept {
|
||||
return terminal.which() != 0;
|
||||
}
|
||||
|
||||
/// Gets a mutable reference to the cycle count for this basic block.
|
||||
size_t& CycleCount();
|
||||
inline size_t& CycleCount() noexcept {
|
||||
return cycle_count;
|
||||
}
|
||||
/// Gets an immutable reference to the cycle count for this basic block.
|
||||
const size_t& CycleCount() const;
|
||||
|
||||
inline const size_t& CycleCount() const noexcept {
|
||||
return cycle_count;
|
||||
}
|
||||
private:
|
||||
/// List of instructions in this block.
|
||||
instruction_list_type instructions;
|
||||
/// Block to execute next if `cond` did not pass.
|
||||
std::optional<LocationDescriptor> cond_failed = {};
|
||||
/// 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;
|
||||
std::unique_ptr<Common::Pool<sizeof(Inst), 2097152UL / sizeof(Inst)>> instruction_alloc_pool;
|
||||
/// Terminal instruction of this block.
|
||||
Terminal terminal = Term::Invalid{};
|
||||
|
||||
/// Number of cycles this block takes to execute if the conditional fails.
|
||||
size_t cond_failed_cycle_count = 0;
|
||||
/// 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);
|
||||
std::string DumpBlock(const IR::Block& block) noexcept;
|
||||
|
||||
} // namespace Dynarmic::IR
|
||||
|
||||
58
src/dynarmic/ir/dense_list.h
Normal file
58
src/dynarmic/ir/dense_list.h
Normal file
@@ -0,0 +1,58 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include <deque>
|
||||
|
||||
namespace Dynarmic {
|
||||
template<typename T> struct dense_list {
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using size_type = std::size_t;
|
||||
using value_type = T;
|
||||
using pointer = value_type*;
|
||||
using const_pointer = const value_type*;
|
||||
using reference = value_type&;
|
||||
using const_reference = const value_type&;
|
||||
using iterator = std::deque<value_type>::iterator;
|
||||
using const_iterator = std::deque<value_type>::const_iterator;
|
||||
using reverse_iterator = std::reverse_iterator<iterator>;
|
||||
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
||||
|
||||
inline bool empty() const noexcept { return list.empty(); }
|
||||
inline size_type size() const noexcept { return list.size(); }
|
||||
|
||||
inline value_type& front() noexcept { return list.front(); }
|
||||
inline const value_type& front() const noexcept { return list.front(); }
|
||||
|
||||
inline value_type& back() noexcept { return list.back(); }
|
||||
inline const value_type& back() const noexcept { return list.back(); }
|
||||
|
||||
inline iterator begin() noexcept { return list.begin(); }
|
||||
inline const_iterator begin() const noexcept { return list.begin(); }
|
||||
inline iterator end() noexcept { return list.end(); }
|
||||
inline const_iterator end() const noexcept { return list.end(); }
|
||||
|
||||
inline reverse_iterator rbegin() noexcept { return list.rbegin(); }
|
||||
inline const_reverse_iterator rbegin() const noexcept { return list.rbegin(); }
|
||||
inline reverse_iterator rend() noexcept { return list.rend(); }
|
||||
inline const_reverse_iterator rend() const noexcept { return list.rend(); }
|
||||
|
||||
inline const_iterator cbegin() const noexcept { return list.cbegin(); }
|
||||
inline const_iterator cend() const noexcept { return list.cend(); }
|
||||
|
||||
inline const_reverse_iterator crbegin() const noexcept { return list.crbegin(); }
|
||||
inline const_reverse_iterator crend() const noexcept { return list.crend(); }
|
||||
|
||||
inline iterator insert_before(iterator it, value_type& value) noexcept {
|
||||
if (it == list.begin()) {
|
||||
list.push_front(value);
|
||||
return list.begin();
|
||||
}
|
||||
auto const index = std::distance(list.begin(), it - 1);
|
||||
list.insert(it - 1, value);
|
||||
return list.begin() + index;
|
||||
}
|
||||
|
||||
std::deque<value_type> list;
|
||||
};
|
||||
}
|
||||
@@ -605,10 +605,6 @@ bool Inst::AreAllArgsImmediates() const {
|
||||
return std::all_of(args.begin(), args.begin() + NumArgs(), [](const auto& value) { return value.IsImmediate(); });
|
||||
}
|
||||
|
||||
bool Inst::HasAssociatedPseudoOperation() const {
|
||||
return next_pseudoop && !IsAPseudoOperation();
|
||||
}
|
||||
|
||||
Inst* Inst::GetAssociatedPseudoOperation(Opcode opcode) {
|
||||
Inst* pseudoop = next_pseudoop;
|
||||
while (pseudoop) {
|
||||
|
||||
@@ -19,14 +19,12 @@ 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.
|
||||
*/
|
||||
/// A representation of a microinstruction. A single ARM/Thumb instruction may be
|
||||
/// converted into zero or more microinstructions.
|
||||
//class Inst final {
|
||||
class Inst final : public mcl::intrusive_list_node<Inst> {
|
||||
public:
|
||||
explicit Inst(Opcode op)
|
||||
: op(op) {}
|
||||
explicit Inst(Opcode op) : op(op) {}
|
||||
|
||||
/// Determines whether or not this instruction performs an arithmetic shift.
|
||||
bool IsArithmeticShift() const;
|
||||
@@ -122,7 +120,9 @@ public:
|
||||
bool HasUses() const { return use_count > 0; }
|
||||
|
||||
/// Determines if there is a pseudo-operation associated with this instruction.
|
||||
bool HasAssociatedPseudoOperation() const;
|
||||
inline bool HasAssociatedPseudoOperation() const noexcept {
|
||||
return next_pseudoop && !IsAPseudoOperation();
|
||||
}
|
||||
/// Gets a pseudo-operation associated with this instruction.
|
||||
Inst* GetAssociatedPseudoOperation(Opcode opcode);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user