basic_block: Add proxy member functions for the instruction list
Currently basic block kind of acts like a 'dumb struct' which makes things a little more verbose to write (as opposed to keeping it all in one place, I guess). It's also a little wonky conceptually, considering a block is composed of instructions (i.e. 'contains' them). So providing accessors that make it act more like a container can make working with algorithms a little nicer. It also makes the API a little more defined. Ideally, the list would be only available through a function, but currently, the pool allocator is exposed, which seems somewhat odd, considering the block itself should manage its overall allocations (with placement new, and regular new), rather than putting that sanitizing directly on the IR emitter (it should just care about emission, not block state). However, recontaining that can be followed up with, as it's very trivial to do.
This commit is contained in:
parent
226d66dd5b
commit
1abe881921
7 changed files with 41 additions and 11 deletions
|
@ -71,7 +71,7 @@ EmitX64::BlockDescriptor EmitX64::Emit(const Arm::LocationDescriptor descriptor,
|
||||||
|
|
||||||
EmitCondPrelude(block);
|
EmitCondPrelude(block);
|
||||||
|
|
||||||
for (auto iter = block.instructions.begin(); iter != block.instructions.end(); ++iter) {
|
for (auto iter = block.begin(); iter != block.end(); ++iter) {
|
||||||
IR::Inst* inst = &*iter;
|
IR::Inst* inst = &*iter;
|
||||||
|
|
||||||
// Call the relevant Emit* member function.
|
// Call the relevant Emit* member function.
|
||||||
|
|
|
@ -57,7 +57,7 @@ std::string DumpBlock(const IR::Block& block) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
for (auto inst = block.instructions.begin(); inst != block.instructions.end(); ++inst) {
|
for (auto inst = block.begin(); inst != block.end(); ++inst) {
|
||||||
const Opcode op = inst->GetOpcode();
|
const Opcode op = inst->GetOpcode();
|
||||||
|
|
||||||
if (GetTypeOf(op) != Type::Void) {
|
if (GetTypeOf(op) != Type::Void) {
|
||||||
|
|
|
@ -29,8 +29,38 @@ namespace IR {
|
||||||
*/
|
*/
|
||||||
class Block final {
|
class Block final {
|
||||||
public:
|
public:
|
||||||
|
using InstructionList = Common::IntrusiveList<Inst>;
|
||||||
|
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 Arm::LocationDescriptor& location) : location(location) {}
|
explicit Block(const Arm::LocationDescriptor& location) : location(location) {}
|
||||||
|
|
||||||
|
bool empty() const { return instructions.empty(); }
|
||||||
|
|
||||||
|
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(); }
|
||||||
|
|
||||||
/// Description of the starting location of this block
|
/// Description of the starting location of this block
|
||||||
Arm::LocationDescriptor location;
|
Arm::LocationDescriptor location;
|
||||||
/// Conditional to pass in order to execute this block
|
/// Conditional to pass in order to execute this block
|
||||||
|
@ -39,7 +69,7 @@ public:
|
||||||
boost::optional<Arm::LocationDescriptor> cond_failed = {};
|
boost::optional<Arm::LocationDescriptor> cond_failed = {};
|
||||||
|
|
||||||
/// List of instructions in this block.
|
/// List of instructions in this block.
|
||||||
Common::IntrusiveList<Inst> instructions;
|
InstructionList instructions;
|
||||||
/// Memory pool for instruction list
|
/// Memory pool for instruction list
|
||||||
std::unique_ptr<Common::Pool> instruction_alloc_pool = std::make_unique<Common::Pool>(sizeof(Inst), 4096);
|
std::unique_ptr<Common::Pool> instruction_alloc_pool = std::make_unique<Common::Pool>(sizeof(Inst), 4096);
|
||||||
/// Terminal instruction of this block.
|
/// Terminal instruction of this block.
|
||||||
|
|
|
@ -66,7 +66,7 @@ bool ArmTranslatorVisitor::ConditionPassed(Cond cond) {
|
||||||
|
|
||||||
// non-AL cond
|
// non-AL cond
|
||||||
|
|
||||||
if (!ir.block.instructions.empty()) {
|
if (!ir.block.empty()) {
|
||||||
// We've already emitted instructions. Quit for now, we'll make a new block here later.
|
// We've already emitted instructions. Quit for now, we'll make a new block here later.
|
||||||
cond_state = ConditionalState::Break;
|
cond_state = ConditionalState::Break;
|
||||||
ir.SetTerm(IR::Term::LinkBlockFast{ir.current_location});
|
ir.SetTerm(IR::Term::LinkBlockFast{ir.current_location});
|
||||||
|
|
|
@ -61,18 +61,18 @@ void DeadCodeElimination(IR::Block& block) {
|
||||||
// We iterate over the instructions in reverse order.
|
// We iterate over the instructions in reverse order.
|
||||||
// This is because removing an instruction reduces the number of uses for earlier instructions.
|
// This is because removing an instruction reduces the number of uses for earlier instructions.
|
||||||
|
|
||||||
if (block.instructions.empty()) {
|
if (block.empty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto iter = block.instructions.end();
|
auto iter = block.end();
|
||||||
do {
|
do {
|
||||||
--iter;
|
--iter;
|
||||||
if (!iter->HasUses() && is_side_effect_free(iter->GetOpcode())) {
|
if (!iter->HasUses() && is_side_effect_free(iter->GetOpcode())) {
|
||||||
iter->Invalidate();
|
iter->Invalidate();
|
||||||
iter = block.instructions.erase(iter);
|
iter = block.instructions.erase(iter);
|
||||||
}
|
}
|
||||||
} while (iter != block.instructions.begin());
|
} while (iter != block.begin());
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Optimization
|
} // namespace Optimization
|
||||||
|
|
|
@ -16,7 +16,7 @@ namespace Dynarmic {
|
||||||
namespace Optimization {
|
namespace Optimization {
|
||||||
|
|
||||||
void GetSetElimination(IR::Block& block) {
|
void GetSetElimination(IR::Block& block) {
|
||||||
using Iterator = decltype(block.instructions.begin());
|
using Iterator = decltype(block.begin());
|
||||||
struct RegisterInfo {
|
struct RegisterInfo {
|
||||||
IR::Value register_value;
|
IR::Value register_value;
|
||||||
bool set_instruction_present = false;
|
bool set_instruction_present = false;
|
||||||
|
@ -47,7 +47,7 @@ void GetSetElimination(IR::Block& block) {
|
||||||
get_inst->ReplaceUsesWith(info.register_value);
|
get_inst->ReplaceUsesWith(info.register_value);
|
||||||
};
|
};
|
||||||
|
|
||||||
for (auto inst = block.instructions.begin(); inst != block.instructions.end(); ++inst) {
|
for (auto inst = block.begin(); inst != block.end(); ++inst) {
|
||||||
switch (inst->GetOpcode()) {
|
switch (inst->GetOpcode()) {
|
||||||
case IR::Opcode::SetRegister: {
|
case IR::Opcode::SetRegister: {
|
||||||
Arm::Reg reg = inst->GetArg(0).GetRegRef();
|
Arm::Reg reg = inst->GetArg(0).GetRegRef();
|
||||||
|
|
|
@ -16,7 +16,7 @@ namespace Dynarmic {
|
||||||
namespace Optimization {
|
namespace Optimization {
|
||||||
|
|
||||||
void VerificationPass(const IR::Block& block) {
|
void VerificationPass(const IR::Block& block) {
|
||||||
for (const auto& inst : block.instructions) {
|
for (const auto& inst : block) {
|
||||||
for (size_t i = 0; i < inst.NumArgs(); i++) {
|
for (size_t i = 0; i < inst.NumArgs(); i++) {
|
||||||
IR::Type t1 = inst.GetArg(i).GetType();
|
IR::Type t1 = inst.GetArg(i).GetType();
|
||||||
IR::Type t2 = IR::GetArgTypeOf(inst.GetOpcode(), i);
|
IR::Type t2 = IR::GetArgTypeOf(inst.GetOpcode(), i);
|
||||||
|
@ -28,7 +28,7 @@ void VerificationPass(const IR::Block& block) {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<IR::Inst*, size_t> actual_uses;
|
std::map<IR::Inst*, size_t> actual_uses;
|
||||||
for (const auto& inst : block.instructions) {
|
for (const auto& inst : block) {
|
||||||
for (size_t i = 0; i < inst.NumArgs(); i++) {
|
for (size_t i = 0; i < inst.NumArgs(); i++) {
|
||||||
if (!inst.GetArg(i).IsImmediate()) {
|
if (!inst.GetArg(i).IsImmediate()) {
|
||||||
actual_uses[inst.GetArg(i).GetInst()]++;
|
actual_uses[inst.GetArg(i).GetInst()]++;
|
||||||
|
|
Loading…
Reference in a new issue