diff --git a/src/ir_opt/constant_propagation_pass.cpp b/src/ir_opt/constant_propagation_pass.cpp index f3a8b60d..b9c6616f 100644 --- a/src/ir_opt/constant_propagation_pass.cpp +++ b/src/ir_opt/constant_propagation_pass.cpp @@ -158,11 +158,16 @@ void FoldMostSignificantBit(IR::Inst& inst) { } void FoldMostSignificantWord(IR::Inst& inst) { + IR::Inst* carry_inst = inst.GetAssociatedPseudoOperation(IR::Opcode::GetCarryFromOp); + if (!inst.AreAllArgsImmediates()) { return; } const auto operand = inst.GetArg(0); + if (carry_inst) { + carry_inst->ReplaceUsesWith(IR::Value{Common::Bit<31>(operand.GetImmediateAsU64())}); + } inst.ReplaceUsesWith(IR::Value{static_cast(operand.GetImmediateAsU64() >> 32)}); } diff --git a/tests/A32/test_arm_instructions.cpp b/tests/A32/test_arm_instructions.cpp new file mode 100644 index 00000000..18cc1e19 --- /dev/null +++ b/tests/A32/test_arm_instructions.cpp @@ -0,0 +1,44 @@ +/* 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 +#include + +#include "A32/testenv.h" + +using namespace Dynarmic; + +static A32::UserConfig GetUserConfig(ArmTestEnv* testenv) { + A32::UserConfig user_config; + user_config.enable_fast_dispatch = false; + user_config.callbacks = testenv; + return user_config; +} + +TEST_CASE("arm: Opt Failure: Const folding in MostSignificantWord", "[arm][A32]") { + // This was a randomized test-case that was failing. + // This was due to constant folding for MostSignificantWord + // failing to take into account an associated GetCarryFromOp + // pseudoinstruction. + + ArmTestEnv test_env; + A32::Jit jit{GetUserConfig(&test_env)}; + test_env.code_mem = { + 0xe30ad071, // movw, sp, #41073 + 0xe75efd3d, // smmulr lr, sp, sp + 0xa637af1e, // shadd16ge r10, r7, lr + 0xf57ff01f, // clrex + 0x86b98879, // sxtahhi r8, r9, r9, ror #16 + 0xeafffffe, // b +#0 + }; + + jit.SetCpsr(0x000001d0); // User-mode + + test_env.ticks_left = 6; + jit.Run(); + + // If we don't trigger the GetCarryFromOp ASSERT, we're fine. +} diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index b53e262d..5c146009 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,5 +1,6 @@ add_executable(dynarmic_tests A32/test_arm_disassembler.cpp + A32/test_arm_instructions.cpp A32/test_thumb_instructions.cpp A32/testenv.h A64/a64.cpp