mirror of
https://git.suyu.dev/suyu/dynarmic.git
synced 2026-03-10 03:06:27 +00:00
Implement some simple IR optimizations (get/set eliminiation and DCE)
This commit is contained in:
37
src/ir_opt/dead_code_elimination_pass.cpp
Normal file
37
src/ir_opt/dead_code_elimination_pass.cpp
Normal file
@@ -0,0 +1,37 @@
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "frontend/ir/ir.h"
|
||||
#include "ir_opt/passes.h"
|
||||
|
||||
namespace Dynarmic {
|
||||
namespace Optimization {
|
||||
|
||||
void DeadCodeElimination(IR::Block& block) {
|
||||
const auto is_side_effect_free = [](IR::Opcode op) -> bool {
|
||||
return IR::GetTypeOf(op) != IR::Type::Void;
|
||||
};
|
||||
|
||||
// We iterate over the instructions in reverse order.
|
||||
// This is because removing an instruction reduces the number of uses for earlier instructions.
|
||||
|
||||
if (block.instructions.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto iter = block.instructions.end();
|
||||
do {
|
||||
--iter;
|
||||
if (!(*iter)->HasUses() && is_side_effect_free((*iter)->GetOpcode())) {
|
||||
(*iter)->Invalidate();
|
||||
iter = block.instructions.erase(iter);
|
||||
}
|
||||
} while (iter != block.instructions.begin());
|
||||
}
|
||||
|
||||
} // namespace Optimization
|
||||
} // namespace Dynarmic
|
||||
108
src/ir_opt/get_set_elimination_pass.cpp
Normal file
108
src/ir_opt/get_set_elimination_pass.cpp
Normal file
@@ -0,0 +1,108 @@
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "frontend/ir/ir.h"
|
||||
#include "ir_opt/passes.h"
|
||||
|
||||
namespace Dynarmic {
|
||||
namespace Optimization {
|
||||
|
||||
void GetSetElimination(IR::Block& block) {
|
||||
using Iterator = decltype(block.instructions.begin());
|
||||
struct RegisterInfo {
|
||||
IR::ValuePtr register_value = nullptr;
|
||||
bool set_instruction_present = false;
|
||||
Iterator last_set_instruction;
|
||||
};
|
||||
std::array<RegisterInfo, 15> reg_info;
|
||||
RegisterInfo n_info;
|
||||
RegisterInfo z_info;
|
||||
RegisterInfo c_info;
|
||||
RegisterInfo v_info;
|
||||
|
||||
const auto do_set = [&block](RegisterInfo& info, IR::ValuePtr value, Iterator set_inst) {
|
||||
if (info.set_instruction_present) {
|
||||
(*info.last_set_instruction)->Invalidate();
|
||||
block.instructions.erase(info.last_set_instruction);
|
||||
}
|
||||
|
||||
info.register_value = value;
|
||||
info.set_instruction_present = true;
|
||||
info.last_set_instruction = set_inst;
|
||||
};
|
||||
|
||||
const auto do_get = [](RegisterInfo& info, Iterator get_inst) {
|
||||
if (!info.register_value) {
|
||||
info.register_value = *get_inst;
|
||||
return;
|
||||
}
|
||||
(*get_inst)->ReplaceUsesWith(info.register_value);
|
||||
};
|
||||
|
||||
for (auto iter = block.instructions.begin(); iter != block.instructions.end(); ++iter) {
|
||||
switch ((*iter)->GetOpcode()) {
|
||||
case IR::Opcode::SetRegister: {
|
||||
auto inst = reinterpret_cast<IR::Inst*>((*iter).get());
|
||||
Arm::Reg reg = reinterpret_cast<IR::ImmRegRef*>(inst->GetArg(0).get())->value;
|
||||
if (reg == Arm::Reg::PC)
|
||||
break;
|
||||
size_t reg_index = static_cast<size_t>(reg);
|
||||
do_set(reg_info[reg_index], inst->GetArg(1), iter);
|
||||
break;
|
||||
}
|
||||
case IR::Opcode::GetRegister: {
|
||||
auto inst = reinterpret_cast<IR::Inst*>((*iter).get());
|
||||
Arm::Reg reg = reinterpret_cast<IR::ImmRegRef*>(inst->GetArg(0).get())->value;
|
||||
ASSERT(reg != Arm::Reg::PC);
|
||||
size_t reg_index = static_cast<size_t>(reg);
|
||||
do_get(reg_info[reg_index], iter);
|
||||
break;
|
||||
}
|
||||
case IR::Opcode::SetNFlag: {
|
||||
auto inst = reinterpret_cast<IR::Inst*>((*iter).get());
|
||||
do_set(n_info, inst->GetArg(0), iter);
|
||||
break;
|
||||
}
|
||||
case IR::Opcode::GetNFlag: {
|
||||
do_get(n_info, iter);
|
||||
break;
|
||||
}
|
||||
case IR::Opcode::SetZFlag: {
|
||||
auto inst = reinterpret_cast<IR::Inst*>((*iter).get());
|
||||
do_set(z_info, inst->GetArg(0), iter);
|
||||
break;
|
||||
}
|
||||
case IR::Opcode::GetZFlag: {
|
||||
do_get(z_info, iter);
|
||||
break;
|
||||
}
|
||||
case IR::Opcode::SetCFlag: {
|
||||
auto inst = reinterpret_cast<IR::Inst*>((*iter).get());
|
||||
do_set(c_info, inst->GetArg(0), iter);
|
||||
break;
|
||||
}
|
||||
case IR::Opcode::GetCFlag: {
|
||||
do_get(c_info, iter);
|
||||
break;
|
||||
}
|
||||
case IR::Opcode::SetVFlag: {
|
||||
auto inst = reinterpret_cast<IR::Inst*>((*iter).get());
|
||||
do_set(v_info, inst->GetArg(0), iter);
|
||||
break;
|
||||
}
|
||||
case IR::Opcode::GetVFlag: {
|
||||
do_get(v_info, iter);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Optimization
|
||||
} // namespace Dynarmic
|
||||
23
src/ir_opt/passes.h
Normal file
23
src/ir_opt/passes.h
Normal file
@@ -0,0 +1,23 @@
|
||||
/* 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
|
||||
|
||||
namespace Dynarmic {
|
||||
namespace IR {
|
||||
class Block;
|
||||
}
|
||||
}
|
||||
|
||||
namespace Dynarmic {
|
||||
namespace Optimization {
|
||||
|
||||
void GetSetElimination(IR::Block& block);
|
||||
void DeadCodeElimination(IR::Block& block);
|
||||
void VerificationPass(const IR::Block& block);
|
||||
|
||||
} // namespace Optimization
|
||||
} // namespace Dynarmic
|
||||
21
src/ir_opt/verification_pass.cpp
Normal file
21
src/ir_opt/verification_pass.cpp
Normal file
@@ -0,0 +1,21 @@
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "frontend/ir/ir.h"
|
||||
#include "ir_opt/passes.h"
|
||||
|
||||
namespace Dynarmic {
|
||||
namespace Optimization {
|
||||
|
||||
void VerificationPass(const IR::Block& block) {
|
||||
for (const auto& inst : block.instructions) {
|
||||
inst->AssertValid();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Optimization
|
||||
} // namespace Dynarmic
|
||||
Reference in New Issue
Block a user