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 reg_info; std::array 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}; }