/* This file is part of the dynarmic project. * Copyright (c) 2016 MerryMage * This software may be used and distributed according to the terms of the GNU * General Public License version 2 or any later version. */ #pragma once #include #include #include #include #include "common/common_types.h" #include "common/intrusive_list.h" #include "common/memory_pool.h" #include "frontend/ir/location_descriptor.h" #include "frontend/ir/microinstruction.h" #include "frontend/ir/terminal.h" #include "frontend/ir/value.h" namespace Dynarmic { namespace IR { 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; 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) : location(location), end_location(location) {} 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 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 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. Arm::Cond GetCondition() const; /// Sets the condition required to pass in order to execute this block. void SetCondition(Arm::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 prediated 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); /// 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 Arm::Cond cond = Arm::Cond::AL; /// Block to execute next if `cond` did not pass. boost::optional 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 instruction_alloc_pool = std::make_unique(sizeof(Inst), 4096); /// 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 IR } // namespace Dynarmic