aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorlizzie <lizzie@eden-emu.dev>2026-02-12 01:32:26 +0100
committercrueter <crueter@eden-emu.dev>2026-02-12 01:32:26 +0100
commitb600b90d53d46e46ac0d17773701ab2fe270fd1c (patch)
treefbee44cf6f856c079a5640956f33a8f3a7ad7a02 /src
parent2b979024cb901099fee264866c135acc59256189 (diff)
[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>
Diffstat (limited to 'src')
-rw-r--r--src/dynarmic/src/dynarmic/ir/opt_passes.cpp75
1 files changed, 37 insertions, 38 deletions
diff --git a/src/dynarmic/src/dynarmic/ir/opt_passes.cpp b/src/dynarmic/src/dynarmic/ir/opt_passes.cpp
index 4929ed5e04..2bd2e3a1d5 100644
--- a/src/dynarmic/src/dynarmic/ir/opt_passes.cpp
+++ b/src/dynarmic/src/dynarmic/ir/opt_passes.cpp
@@ -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) {
using Iterator = IR::Block::iterator;
@@ -501,8 +511,8 @@ static void A64GetSetElimination(IR::Block& block) {
struct RegisterInfo {
IR::Value register_value;
TrackingType tracking_type;
- bool set_instruction_present = false;
Iterator last_set_instruction;
+ bool set_instruction_present = false;
};
std::array<RegisterInfo, 31> reg_info;
std::array<RegisterInfo, 32> vec_info;
@@ -514,59 +524,58 @@ static void A64GetSetElimination(IR::Block& block) {
info.last_set_instruction->Invalidate();
block.Instructions().erase(info.last_set_instruction);
}
-
info.register_value = value;
info.tracking_type = tracking_type;
info.set_instruction_present = true;
info.last_set_instruction = set_inst;
};
-
- const auto do_get = [](RegisterInfo& info, Iterator get_inst, TrackingType tracking_type) {
- const auto do_nothing = [&] {
+ const auto do_get = [&block](RegisterInfo& info, Iterator get_inst, TrackingType tracking_type) {
+ if (!info.register_value.IsEmpty() && info.tracking_type == tracking_type) {
+ 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.register_value = IR::Value(&*get_inst);
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) {
auto const opcode = inst->GetOpcode();
switch (opcode) {
case IR::Opcode::A64GetW: {
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;
}
case IR::Opcode::A64GetX: {
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;
}
case IR::Opcode::A64GetS: {
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;
}
case IR::Opcode::A64GetD: {
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;
}
case IR::Opcode::A64GetQ: {
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;
}
case IR::Opcode::A64GetSP: {
@@ -579,27 +588,27 @@ static void A64GetSetElimination(IR::Block& block) {
}
case IR::Opcode::A64SetW: {
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;
}
case IR::Opcode::A64SetX: {
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;
}
case IR::Opcode::A64SetS: {
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;
}
case IR::Opcode::A64SetD: {
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;
}
case IR::Opcode::A64SetQ: {
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;
}
case IR::Opcode::A64SetSP: {
@@ -668,16 +677,6 @@ static void A64MergeInterpretBlocksPass(IR::Block& block, A64::UserCallbacks* cb
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) {
return is_32_bit ? IR::Value{u32(value)} : IR::Value{value};
}