diff --git a/externals/dynarmic/src/dynarmic/backend/x64/emit_x64_data_processing.cpp b/externals/dynarmic/src/dynarmic/backend/x64/emit_x64_data_processing.cpp index 515f0743d0..7e03e3dcd1 100644 --- a/externals/dynarmic/src/dynarmic/backend/x64/emit_x64_data_processing.cpp +++ b/externals/dynarmic/src/dynarmic/backend/x64/emit_x64_data_processing.cpp @@ -1568,14 +1568,14 @@ void EmitX64::EmitCountLeadingZeros32(EmitContext& ctx, IR::Inst* inst) { } else { const Xbyak::Reg32 source = ctx.reg_alloc.UseScratchGpr(args[0]).cvt32(); const Xbyak::Reg32 result = ctx.reg_alloc.ScratchGpr().cvt32(); + const Xbyak::Reg32 temp = ctx.reg_alloc.ScratchGpr().cvt32(); // The result of a bsr of zero is undefined, but zf is set after it. code.bsr(result, source); - code.mov(source, 0xFFFFFFFF); - code.cmovz(result, source); - code.neg(result); - code.add(result, 31); - + code.mov(temp, 32); + code.xor_(result, 31); + code.test(source, source); + code.cmove(result, temp); ctx.reg_alloc.DefineValue(inst, result); } } @@ -1592,14 +1592,14 @@ void EmitX64::EmitCountLeadingZeros64(EmitContext& ctx, IR::Inst* inst) { } else { const Xbyak::Reg64 source = ctx.reg_alloc.UseScratchGpr(args[0]).cvt64(); const Xbyak::Reg64 result = ctx.reg_alloc.ScratchGpr().cvt64(); + const Xbyak::Reg64 temp = ctx.reg_alloc.ScratchGpr().cvt64(); // The result of a bsr of zero is undefined, but zf is set after it. code.bsr(result, source); - code.mov(source.cvt32(), 0xFFFFFFFF); - code.cmovz(result.cvt32(), source.cvt32()); - code.neg(result.cvt32()); - code.add(result.cvt32(), 63); - + code.mov(temp.cvt32(), 64); + code.xor_(result.cvt32(), 63); + code.test(source, source); + code.cmove(result.cvt32(), temp.cvt32()); ctx.reg_alloc.DefineValue(inst, result); } } diff --git a/externals/dynarmic/tests/A64/a64.cpp b/externals/dynarmic/tests/A64/a64.cpp index 8de3cf9fb6..fefb8a32a2 100644 --- a/externals/dynarmic/tests/A64/a64.cpp +++ b/externals/dynarmic/tests/A64/a64.cpp @@ -2345,3 +2345,43 @@ TEST_CASE("A64: RBIT{16b}", "[a64]") { REQUIRE(jit.GetVector(2)[0] == 0xcafedead); REQUIRE(jit.GetVector(2)[1] == 0xbabebeef); } + +TEST_CASE("A64: CLZ{X}", "[a64]") { + A64TestEnv env; + A64::UserConfig conf{}; + conf.callbacks = &env; + A64::Jit jit{conf}; + env.code_mem.emplace_back(0xdac01060); // clz x0, x3 + env.code_mem.emplace_back(0xdac01081); // clz x1, x4 + env.code_mem.emplace_back(0xdac010a2); // clz x2, x5 + env.code_mem.emplace_back(0x14000000); // b . + jit.SetRegister(3, 0xfffffffffffffff0); + jit.SetRegister(4, 0x0fffffff0ffffff0); + jit.SetRegister(5, 0x07fffffeffeffef0); + jit.SetPC(0); // at _start + env.ticks_left = 4; + jit.Run(); + REQUIRE(jit.GetRegister(0) == 0); + REQUIRE(jit.GetRegister(1) == 4); + REQUIRE(jit.GetRegister(2) == 5); +} + +TEST_CASE("A64: CLZ{W}", "[a64]") { + A64TestEnv env; + A64::UserConfig conf{}; + conf.callbacks = &env; + A64::Jit jit{conf}; + env.code_mem.emplace_back(0x5ac01060); // clz w0, w3 + env.code_mem.emplace_back(0x5ac01081); // clz w1, w4 + env.code_mem.emplace_back(0x5ac010a2); // clz w2, w5 + env.code_mem.emplace_back(0x14000000); // b . + jit.SetRegister(3, 0xffff1110); + jit.SetRegister(4, 0x0fff1110); + jit.SetRegister(5, 0x07fffffe); + jit.SetPC(0); // at _start + env.ticks_left = 4; + jit.Run(); + REQUIRE(jit.GetRegister(0) == 0); + REQUIRE(jit.GetRegister(1) == 4); + REQUIRE(jit.GetRegister(2) == 5); +}