[dynarmic] Make SetX/GetW pairs optimized by getSet pass (#3518)
this results in removed reloads for any code that uses those heavily :) Signed-off-by: lizzie <lizzie@eden-emu.dev> Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3518 Reviewed-by: DraVee <dravee@eden-emu.dev> Reviewed-by: CamilleLaVey <camillelavey99@gmail.com> Co-authored-by: lizzie <lizzie@eden-emu.dev> Co-committed-by: lizzie <lizzie@eden-emu.dev>
This commit is contained in:
parent
2b979024cb
commit
b600b90d53
|
|
@ -485,6 +485,16 @@ static void A64CallbackConfigPass(IR::Block& block, const A64::UserConfig& conf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tiny helper to avoid the need to store based off the opcode
|
||||||
|
// bit size all over the place within folding functions.
|
||||||
|
static void ReplaceUsesWith(IR::Inst& inst, bool is_32_bit, u64 value) {
|
||||||
|
if (is_32_bit) {
|
||||||
|
inst.ReplaceUsesWith(IR::Value{u32(value)});
|
||||||
|
} else {
|
||||||
|
inst.ReplaceUsesWith(IR::Value{value});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void A64GetSetElimination(IR::Block& block) {
|
static void A64GetSetElimination(IR::Block& block) {
|
||||||
using Iterator = IR::Block::iterator;
|
using Iterator = IR::Block::iterator;
|
||||||
|
|
||||||
|
|
@ -501,8 +511,8 @@ static void A64GetSetElimination(IR::Block& block) {
|
||||||
struct RegisterInfo {
|
struct RegisterInfo {
|
||||||
IR::Value register_value;
|
IR::Value register_value;
|
||||||
TrackingType tracking_type;
|
TrackingType tracking_type;
|
||||||
bool set_instruction_present = false;
|
|
||||||
Iterator last_set_instruction;
|
Iterator last_set_instruction;
|
||||||
|
bool set_instruction_present = false;
|
||||||
};
|
};
|
||||||
std::array<RegisterInfo, 31> reg_info;
|
std::array<RegisterInfo, 31> reg_info;
|
||||||
std::array<RegisterInfo, 32> vec_info;
|
std::array<RegisterInfo, 32> vec_info;
|
||||||
|
|
@ -514,59 +524,58 @@ static void A64GetSetElimination(IR::Block& block) {
|
||||||
info.last_set_instruction->Invalidate();
|
info.last_set_instruction->Invalidate();
|
||||||
block.Instructions().erase(info.last_set_instruction);
|
block.Instructions().erase(info.last_set_instruction);
|
||||||
}
|
}
|
||||||
|
|
||||||
info.register_value = value;
|
info.register_value = value;
|
||||||
info.tracking_type = tracking_type;
|
info.tracking_type = tracking_type;
|
||||||
info.set_instruction_present = true;
|
info.set_instruction_present = true;
|
||||||
info.last_set_instruction = set_inst;
|
info.last_set_instruction = set_inst;
|
||||||
};
|
};
|
||||||
|
const auto do_get = [&block](RegisterInfo& info, Iterator get_inst, TrackingType tracking_type) {
|
||||||
const auto do_get = [](RegisterInfo& info, Iterator get_inst, TrackingType tracking_type) {
|
if (!info.register_value.IsEmpty() && info.tracking_type == tracking_type) {
|
||||||
const auto do_nothing = [&] {
|
get_inst->ReplaceUsesWith(info.register_value);
|
||||||
|
} else if (!info.register_value.IsEmpty()
|
||||||
|
&& tracking_type == TrackingType::W
|
||||||
|
&& info.tracking_type == TrackingType::X) {
|
||||||
|
// A sequence like
|
||||||
|
// SetX r1 -> GetW r1, is just reading off the lowest 32-bits of the register
|
||||||
|
if (info.register_value.IsImmediate()) {
|
||||||
|
ReplaceUsesWith(*get_inst, true, u32(info.register_value.GetImmediateAsU64()));
|
||||||
|
} else {
|
||||||
|
A64::IREmitter ir{block};
|
||||||
|
ir.SetInsertionPointBefore(&*get_inst);
|
||||||
|
get_inst->ReplaceUsesWith(ir.LeastSignificantWord(IR::U64{info.register_value}));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
info = {};
|
info = {};
|
||||||
info.register_value = IR::Value(&*get_inst);
|
info.register_value = IR::Value(&*get_inst);
|
||||||
info.tracking_type = tracking_type;
|
info.tracking_type = tracking_type;
|
||||||
};
|
|
||||||
|
|
||||||
if (info.register_value.IsEmpty()) {
|
|
||||||
do_nothing();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info.tracking_type == tracking_type) {
|
|
||||||
get_inst->ReplaceUsesWith(info.register_value);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
do_nothing();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
for (auto inst = block.instructions.begin(); inst != block.instructions.end(); ++inst) {
|
for (auto inst = block.instructions.begin(); inst != block.instructions.end(); ++inst) {
|
||||||
auto const opcode = inst->GetOpcode();
|
auto const opcode = inst->GetOpcode();
|
||||||
switch (opcode) {
|
switch (opcode) {
|
||||||
case IR::Opcode::A64GetW: {
|
case IR::Opcode::A64GetW: {
|
||||||
const size_t index = A64::RegNumber(inst->GetArg(0).GetA64RegRef());
|
const size_t index = A64::RegNumber(inst->GetArg(0).GetA64RegRef());
|
||||||
do_get(reg_info.at(index), inst, TrackingType::W);
|
do_get(reg_info[index], inst, TrackingType::W);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case IR::Opcode::A64GetX: {
|
case IR::Opcode::A64GetX: {
|
||||||
const size_t index = A64::RegNumber(inst->GetArg(0).GetA64RegRef());
|
const size_t index = A64::RegNumber(inst->GetArg(0).GetA64RegRef());
|
||||||
do_get(reg_info.at(index), inst, TrackingType::X);
|
do_get(reg_info[index], inst, TrackingType::X);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case IR::Opcode::A64GetS: {
|
case IR::Opcode::A64GetS: {
|
||||||
const size_t index = A64::VecNumber(inst->GetArg(0).GetA64VecRef());
|
const size_t index = A64::VecNumber(inst->GetArg(0).GetA64VecRef());
|
||||||
do_get(vec_info.at(index), inst, TrackingType::S);
|
do_get(vec_info[index], inst, TrackingType::S);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case IR::Opcode::A64GetD: {
|
case IR::Opcode::A64GetD: {
|
||||||
const size_t index = A64::VecNumber(inst->GetArg(0).GetA64VecRef());
|
const size_t index = A64::VecNumber(inst->GetArg(0).GetA64VecRef());
|
||||||
do_get(vec_info.at(index), inst, TrackingType::D);
|
do_get(vec_info[index], inst, TrackingType::D);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case IR::Opcode::A64GetQ: {
|
case IR::Opcode::A64GetQ: {
|
||||||
const size_t index = A64::VecNumber(inst->GetArg(0).GetA64VecRef());
|
const size_t index = A64::VecNumber(inst->GetArg(0).GetA64VecRef());
|
||||||
do_get(vec_info.at(index), inst, TrackingType::Q);
|
do_get(vec_info[index], inst, TrackingType::Q);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case IR::Opcode::A64GetSP: {
|
case IR::Opcode::A64GetSP: {
|
||||||
|
|
@ -579,27 +588,27 @@ static void A64GetSetElimination(IR::Block& block) {
|
||||||
}
|
}
|
||||||
case IR::Opcode::A64SetW: {
|
case IR::Opcode::A64SetW: {
|
||||||
const size_t index = A64::RegNumber(inst->GetArg(0).GetA64RegRef());
|
const size_t index = A64::RegNumber(inst->GetArg(0).GetA64RegRef());
|
||||||
do_set(reg_info.at(index), inst->GetArg(1), inst, TrackingType::W);
|
do_set(reg_info[index], inst->GetArg(1), inst, TrackingType::W);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case IR::Opcode::A64SetX: {
|
case IR::Opcode::A64SetX: {
|
||||||
const size_t index = A64::RegNumber(inst->GetArg(0).GetA64RegRef());
|
const size_t index = A64::RegNumber(inst->GetArg(0).GetA64RegRef());
|
||||||
do_set(reg_info.at(index), inst->GetArg(1), inst, TrackingType::X);
|
do_set(reg_info[index], inst->GetArg(1), inst, TrackingType::X);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case IR::Opcode::A64SetS: {
|
case IR::Opcode::A64SetS: {
|
||||||
const size_t index = A64::VecNumber(inst->GetArg(0).GetA64VecRef());
|
const size_t index = A64::VecNumber(inst->GetArg(0).GetA64VecRef());
|
||||||
do_set(vec_info.at(index), inst->GetArg(1), inst, TrackingType::S);
|
do_set(vec_info[index], inst->GetArg(1), inst, TrackingType::S);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case IR::Opcode::A64SetD: {
|
case IR::Opcode::A64SetD: {
|
||||||
const size_t index = A64::VecNumber(inst->GetArg(0).GetA64VecRef());
|
const size_t index = A64::VecNumber(inst->GetArg(0).GetA64VecRef());
|
||||||
do_set(vec_info.at(index), inst->GetArg(1), inst, TrackingType::D);
|
do_set(vec_info[index], inst->GetArg(1), inst, TrackingType::D);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case IR::Opcode::A64SetQ: {
|
case IR::Opcode::A64SetQ: {
|
||||||
const size_t index = A64::VecNumber(inst->GetArg(0).GetA64VecRef());
|
const size_t index = A64::VecNumber(inst->GetArg(0).GetA64VecRef());
|
||||||
do_set(vec_info.at(index), inst->GetArg(1), inst, TrackingType::Q);
|
do_set(vec_info[index], inst->GetArg(1), inst, TrackingType::Q);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case IR::Opcode::A64SetSP: {
|
case IR::Opcode::A64SetSP: {
|
||||||
|
|
@ -668,16 +677,6 @@ static void A64MergeInterpretBlocksPass(IR::Block& block, A64::UserCallbacks* cb
|
||||||
|
|
||||||
using Op = Dynarmic::IR::Opcode;
|
using Op = Dynarmic::IR::Opcode;
|
||||||
|
|
||||||
// Tiny helper to avoid the need to store based off the opcode
|
|
||||||
// bit size all over the place within folding functions.
|
|
||||||
static void ReplaceUsesWith(IR::Inst& inst, bool is_32_bit, u64 value) {
|
|
||||||
if (is_32_bit) {
|
|
||||||
inst.ReplaceUsesWith(IR::Value{u32(value)});
|
|
||||||
} else {
|
|
||||||
inst.ReplaceUsesWith(IR::Value{value});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static IR::Value Value(bool is_32_bit, u64 value) {
|
static IR::Value Value(bool is_32_bit, u64 value) {
|
||||||
return is_32_bit ? IR::Value{u32(value)} : IR::Value{value};
|
return is_32_bit ? IR::Value{u32(value)} : IR::Value{value};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue