mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2025-07-20 08:15:46 +00:00
183 lines
7.2 KiB
C++
183 lines
7.2 KiB
C++
/* 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 <mcl/container/intrusive_list.hpp>
|
|
#include <mcl/stdint.hpp>
|
|
|
|
#include "dynarmic/ir/location_descriptor.h"
|
|
#include "dynarmic/ir/microinstruction.h"
|
|
#include "dynarmic/ir/terminal.h"
|
|
#include "dynarmic/ir/value.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.
|
|
class Block final {
|
|
public:
|
|
//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() = default;
|
|
Block(const Block&) = delete;
|
|
Block& operator=(const Block&) = delete;
|
|
Block(Block&&) = default;
|
|
Block& operator=(Block&&) = default;
|
|
|
|
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.
|
|
inline void AppendNewInst(const Opcode opcode, const std::initializer_list<IR::Value> args) noexcept {
|
|
PrependNewInst(instructions.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.
|
|
inline instruction_list_type& Instructions() noexcept {
|
|
return instructions;
|
|
}
|
|
/// Gets an immutable reference to the instruction list for this basic block.
|
|
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.
|
|
inline Terminal GetTerminal() const noexcept {
|
|
return terminal;
|
|
}
|
|
/// Sets the terminal instruction for this basic block.
|
|
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.
|
|
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.
|
|
inline bool HasTerminal() const noexcept {
|
|
return terminal.which() != 0;
|
|
}
|
|
|
|
/// Gets a mutable reference to the cycle count for this basic block.
|
|
inline size_t& CycleCount() noexcept {
|
|
return cycle_count;
|
|
}
|
|
/// Gets an immutable reference to the cycle count for this basic block.
|
|
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;
|
|
/// 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) noexcept;
|
|
|
|
} // namespace Dynarmic::IR
|