From ed86f1d725cf77247f0b37c1c7e58fe2b82cad59 Mon Sep 17 00:00:00 2001 From: 987123879113 <63495610+987123879113@users.noreply.github.com> Date: Tue, 14 Jan 2025 19:19:04 +0900 Subject: DRC: Calculate negative and zero flags for shifts/rotates with a zero shift count. (#13232) * cpu/drcbec.cpp, cpu/drcbearm64.cpp, cpu/drcbex64.cpp, cpu/drcbex86.cpp: Calculate NZ flags for shifts/rotates by 0 bits. * cpu/drcbex86.cpp: Fixed flag calculation for 64-bit multiplication when result is zero. --- src/devices/cpu/drcbearm64.cpp | 103 +++++++-------- src/devices/cpu/drcbec.cpp | 56 ++------ src/devices/cpu/drcbex64.cpp | 40 +++--- src/devices/cpu/drcbex86.cpp | 284 +++++++++++++++++++++++++++-------------- 4 files changed, 273 insertions(+), 210 deletions(-) diff --git a/src/devices/cpu/drcbearm64.cpp b/src/devices/cpu/drcbearm64.cpp index b20359aab07..bc956d84c38 100644 --- a/src/devices/cpu/drcbearm64.cpp +++ b/src/devices/cpu/drcbearm64.cpp @@ -810,9 +810,14 @@ void drcbe_arm64::get_shifted_bit(a64::Assembler &a, const a64::Gp &dst, const a void drcbe_arm64::calculate_carry_shift_left(a64::Assembler &a, const a64::Gp ®, const a64::Gp &shift, int maxBits) const { - Label skip = a.newLabel(); - a.cbz(shift, skip); + Label calc = a.newLabel(); + Label end = a.newLabel(); + + a.cbnz(shift, calc); + store_carry_reg(a, a64::xzr); + a.b(end); + a.bind(calc); const a64::Gp scratch = select_register(SCRATCH_REG1, reg.isGpW() ? 4 : 8); // carry = ((PARAM1 << (shift - 1)) >> maxBits) & 1 @@ -821,13 +826,16 @@ void drcbe_arm64::calculate_carry_shift_left(a64::Assembler &a, const a64::Gp &r a.lsr(scratch, reg, scratch); store_carry_reg(a, scratch); - a.bind(skip); + a.bind(end); } void drcbe_arm64::calculate_carry_shift_left_imm(a64::Assembler &a, const a64::Gp ®, const int shift, int maxBits) const { if (shift == 0) + { + store_carry_reg(a, a64::xzr); return; + } const a64::Gp scratch = select_register(SCRATCH_REG1, reg.isGpW() ? 4 : 8); @@ -838,9 +846,14 @@ void drcbe_arm64::calculate_carry_shift_left_imm(a64::Assembler &a, const a64::G void drcbe_arm64::calculate_carry_shift_right(a64::Assembler &a, const a64::Gp ®, const a64::Gp &shift) const { - Label skip = a.newLabel(); - a.cbz(shift, skip); + Label calc = a.newLabel(); + Label end = a.newLabel(); + + a.cbnz(shift, calc); + store_carry_reg(a, a64::xzr); + a.b(end); + a.bind(calc); const a64::Gp scratch = select_register(SCRATCH_REG1, reg.isGpW() ? 4 : 8); // carry = (PARAM1 >> (shift - 1)) & 1 @@ -848,13 +861,16 @@ void drcbe_arm64::calculate_carry_shift_right(a64::Assembler &a, const a64::Gp & a.lsr(scratch, reg, scratch); store_carry_reg(a, scratch); - a.bind(skip); + a.bind(end); } void drcbe_arm64::calculate_carry_shift_right_imm(a64::Assembler &a, const a64::Gp ®, const int shift) const { if (shift == 0) + { + store_carry_reg(a, a64::xzr); return; + } const a64::Gp scratch = select_register(SCRATCH_REG1, reg.isGpW() ? 4 : 8); @@ -3517,16 +3533,10 @@ template void drcbe_arm64::op_shift(a64::Assembler &a, co a.emit(Opcode, dst, src, shift); - if (shift != 0) - { - if (Opcode == a64::Inst::kIdRor || Opcode == a64::Inst::kIdLsr || Opcode == a64::Inst::kIdAsr) - calculate_carry_shift_right_imm(a, src, shift); - else if (Opcode == a64::Inst::kIdLsl) - calculate_carry_shift_left_imm(a, src, shift, maxBits); - - if (inst.flags()) - a.tst(dst, dst); - } + if (Opcode == a64::Inst::kIdRor || Opcode == a64::Inst::kIdLsr || Opcode == a64::Inst::kIdAsr) + calculate_carry_shift_right_imm(a, src, shift); + else if (Opcode == a64::Inst::kIdLsl) + calculate_carry_shift_left_imm(a, src, shift, maxBits); } else { @@ -3536,20 +3546,15 @@ template void drcbe_arm64::op_shift(a64::Assembler &a, co a.emit(Opcode, dst, src, scratch); - Label skip = a.newLabel(); - a.cbz(scratch, skip); - if (Opcode == a64::Inst::kIdRor || Opcode == a64::Inst::kIdLsr || Opcode == a64::Inst::kIdAsr) calculate_carry_shift_right(a, src, scratch); else if (Opcode == a64::Inst::kIdLsl) calculate_carry_shift_left(a, src, scratch, maxBits); - - if (inst.flags()) - a.tst(dst, dst); - - a.bind(skip); } + if (inst.flags()) + a.tst(dst, dst); + // save dst after using inputs for calculations so the registers have no chance of being overwritten mov_param_reg(a, inst.size(), dstp, dst); } @@ -3594,18 +3599,10 @@ void drcbe_arm64::op_rol(a64::Assembler &a, const uml::instruction &inst) a.ror(output, param, s2); } - if (s != 0) - { - calculate_carry_shift_left_imm(a, param, s, maxBits); - - if (inst.flags()) - a.tst(output, output); - } + calculate_carry_shift_left_imm(a, param, s, maxBits); } else { - Label skip = a.newLabel(); - mov_reg_param(a, inst.size(), shift, src2p); const a64::Gp scratch = select_register(SCRATCH_REG1, inst.size()); @@ -3614,16 +3611,12 @@ void drcbe_arm64::op_rol(a64::Assembler &a, const uml::instruction &inst) a.sub(scratch, scratch, scratch2); a.ror(output, param, scratch); - a.cbz(scratch2, skip); - calculate_carry_shift_left(a, param, scratch2, maxBits); - - if (inst.flags()) - a.tst(output, output); - - a.bind(skip); } + if (inst.flags()) + a.tst(output, output); + mov_param_reg(a, inst.size(), dstp, output); } @@ -3666,14 +3659,13 @@ void drcbe_arm64::op_rolc(a64::Assembler &a, const uml::instruction &inst) a.bfi(output.x(), FLAGS_REG, shift - 1, 1); a.bfi(output, param1, shift, (inst.size() * 8) - shift); a.bfi(FLAGS_REG, carry.x(), 0, 1); - - if (inst.flags()) - a.tst(output, output); } else { a.mov(output, param1); } + + calculate_carry_shift_left_imm(a, param1, shift, maxBits); } else { @@ -3708,14 +3700,14 @@ void drcbe_arm64::op_rolc(a64::Assembler &a, const uml::instruction &inst) a.orr(output, output, carry); - calculate_carry_shift_left(a, param1, scratch2, maxBits); - - if (inst.flags()) - a.tst(output, output); - a.bind(skip3); + + calculate_carry_shift_left(a, param1, scratch2, maxBits); } + if (inst.flags()) + a.tst(output, output); + mov_param_reg(a, inst.size(), dstp, output); } @@ -3760,14 +3752,13 @@ void drcbe_arm64::op_rorc(a64::Assembler &a, const uml::instruction &inst) if (shift > 1) a.bfi(output, param1, (inst.size() * 8) - shift + 1, shift - 1); a.bfi(FLAGS_REG, carry.x(), 0, 1); - - if (inst.flags()) - a.tst(output, output); } else { a.mov(output, param1); } + + calculate_carry_shift_right_imm(a, param1, shift); } else { @@ -3803,14 +3794,14 @@ void drcbe_arm64::op_rorc(a64::Assembler &a, const uml::instruction &inst) a.orr(output, output, carry); - calculate_carry_shift_right(a, param1, scratch2); - - if (inst.flags()) - a.tst(output, output); - a.bind(skip3); + + calculate_carry_shift_right(a, param1, scratch2); } + if (inst.flags()) + a.tst(output, output); + mov_param_reg(a, inst.size(), dstp, output); } diff --git a/src/devices/cpu/drcbec.cpp b/src/devices/cpu/drcbec.cpp index 5e93429dbf6..82cfc10979a 100644 --- a/src/devices/cpu/drcbec.cpp +++ b/src/devices/cpu/drcbec.cpp @@ -1187,11 +1187,9 @@ int drcbe_c::execute(code_handle &entry) case MAKE_OPCODE_SHORT(OP_SHL, 4, 1): shift = PARAM2 & 31; temp32 = PARAM1 << shift; + flags = FLAGS32_NZ(temp32); if (shift != 0) - { - flags = FLAGS32_NZ(temp32); flags |= ((PARAM1 << (shift - 1)) >> 31) & FLAG_C; - } PARAM0 = temp32; break; @@ -1202,11 +1200,9 @@ int drcbe_c::execute(code_handle &entry) case MAKE_OPCODE_SHORT(OP_SHR, 4, 1): shift = PARAM2 & 31; temp32 = PARAM1 >> shift; + flags = FLAGS32_NZ(temp32); if (shift != 0) - { - flags = FLAGS32_NZ(temp32); flags |= (PARAM1 >> (shift - 1)) & FLAG_C; - } PARAM0 = temp32; break; @@ -1217,11 +1213,9 @@ int drcbe_c::execute(code_handle &entry) case MAKE_OPCODE_SHORT(OP_SAR, 4, 1): shift = PARAM2 & 31; temp32 = (int32_t)PARAM1 >> shift; + flags = FLAGS32_NZ(temp32); if (shift != 0) - { - flags = FLAGS32_NZ(temp32); flags |= (PARAM1 >> (shift - 1)) & FLAG_C; - } PARAM0 = temp32; break; @@ -1232,11 +1226,9 @@ int drcbe_c::execute(code_handle &entry) case MAKE_OPCODE_SHORT(OP_ROL, 4, 1): shift = PARAM2 & 31; temp32 = rotl_32(PARAM1, shift); + flags = FLAGS32_NZ(temp32); if (shift != 0) - { - flags = FLAGS32_NZ(temp32); flags |= ((PARAM1 << (shift - 1)) >> 31) & FLAG_C; - } PARAM0 = temp32; break; @@ -1258,11 +1250,9 @@ int drcbe_c::execute(code_handle &entry) temp32 = (PARAM1 << shift) | (flags & FLAG_C); else temp32 = PARAM1; + flags = FLAGS32_NZ(temp32); if (shift != 0) - { - flags = FLAGS32_NZ(temp32); flags |= ((PARAM1 << (shift - 1)) >> 31) & FLAG_C; - } PARAM0 = temp32; break; @@ -1273,11 +1263,9 @@ int drcbe_c::execute(code_handle &entry) case MAKE_OPCODE_SHORT(OP_ROR, 4, 1): shift = PARAM2 & 31; temp32 = rotr_32(PARAM1, shift); + flags = FLAGS32_NZ(temp32); if (shift != 0) - { - flags = FLAGS32_NZ(temp32); flags |= (PARAM1 >> (shift - 1)) & FLAG_C; - } PARAM0 = temp32; break; @@ -1299,11 +1287,9 @@ int drcbe_c::execute(code_handle &entry) temp32 = (PARAM1 >> shift) | ((flags & FLAG_C) << 31); else temp32 = PARAM1; + flags = FLAGS32_NZ(temp32); if (shift != 0) - { - flags = FLAGS32_NZ(temp32); flags |= (PARAM1 >> (shift - 1)) & FLAG_C; - } PARAM0 = temp32; break; @@ -1823,11 +1809,9 @@ int drcbe_c::execute(code_handle &entry) case MAKE_OPCODE_SHORT(OP_SHL, 8, 1): shift = DPARAM2 & 63; temp64 = DPARAM1 << shift; + flags = FLAGS64_NZ(temp64); if (shift != 0) - { - flags = FLAGS64_NZ(temp64); flags |= ((DPARAM1 << (shift - 1)) >> 63) & FLAG_C; - } DPARAM0 = temp64; break; @@ -1838,11 +1822,9 @@ int drcbe_c::execute(code_handle &entry) case MAKE_OPCODE_SHORT(OP_SHR, 8, 1): shift = DPARAM2 & 63; temp64 = DPARAM1 >> shift; + flags = FLAGS64_NZ(temp64); if (shift != 0) - { - flags = FLAGS64_NZ(temp64); flags |= (DPARAM1 >> (shift - 1)) & FLAG_C; - } DPARAM0 = temp64; break; @@ -1853,11 +1835,9 @@ int drcbe_c::execute(code_handle &entry) case MAKE_OPCODE_SHORT(OP_SAR, 8, 1): shift = DPARAM2 & 63; temp64 = (int64_t)DPARAM1 >> shift; + flags = FLAGS64_NZ(temp64); if (shift != 0) - { - flags = FLAGS64_NZ(temp64); flags |= (DPARAM1 >> (shift - 1)) & FLAG_C; - } DPARAM0 = temp64; break; @@ -1868,11 +1848,9 @@ int drcbe_c::execute(code_handle &entry) case MAKE_OPCODE_SHORT(OP_ROL, 8, 1): shift = DPARAM2 & 63; temp64 = rotl_64(DPARAM1, shift); + flags = FLAGS64_NZ(temp64); if (shift != 0) - { - flags = FLAGS64_NZ(temp64); flags |= ((DPARAM1 << (shift - 1)) >> 63) & FLAG_C; - } DPARAM0 = temp64; break; @@ -1894,11 +1872,9 @@ int drcbe_c::execute(code_handle &entry) temp64 = (DPARAM1 << shift) | (flags & FLAG_C); else temp64 = DPARAM1; + flags = FLAGS64_NZ(temp64); if (shift != 0) - { - flags = FLAGS64_NZ(temp64); flags |= ((DPARAM1 << (shift - 1)) >> 63) & FLAG_C; - } DPARAM0 = temp64; break; @@ -1909,11 +1885,9 @@ int drcbe_c::execute(code_handle &entry) case MAKE_OPCODE_SHORT(OP_ROR, 8, 1): shift = DPARAM2 & 63; temp64 = rotr_64(DPARAM1, shift); + flags = FLAGS64_NZ(temp64); if (shift != 0) - { - flags = FLAGS64_NZ(temp64); flags |= (DPARAM1 >> (shift - 1)) & FLAG_C; - } DPARAM0 = temp64; break; @@ -1935,11 +1909,9 @@ int drcbe_c::execute(code_handle &entry) temp64 = (DPARAM1 >> shift) | (((uint64_t)flags & FLAG_C) << 63); else temp64 = DPARAM1; + flags = FLAGS64_NZ(temp64); if (shift != 0) - { - flags = FLAGS64_NZ(temp64); flags |= (DPARAM1 >> (shift - 1)) & FLAG_C; - } DPARAM0 = temp64; break; diff --git a/src/devices/cpu/drcbex64.cpp b/src/devices/cpu/drcbex64.cpp index 5e08d498443..aa7b3dc68e2 100644 --- a/src/devices/cpu/drcbex64.cpp +++ b/src/devices/cpu/drcbex64.cpp @@ -1162,52 +1162,54 @@ void drcbe_x64::shift_op_param(Assembler &a, Inst::Id const opcode, size_t opsiz { if (param.is_immediate()) { - if ((param.immediate() & (opsize * 8 - 1)) == 0) - return; + const uint32_t bitshift = param.immediate() & (opsize * 8 - 1); - a.emit(opcode, dst, imm(param.immediate())); + if (bitshift != 0) + a.emit(opcode, dst, imm(param.immediate())); if (update_flags) - calculate_status_flags(a, opsize, dst, FLAG_S | FLAG_Z); // calculate status flags but preserve carry + { + if (bitshift == 0) + a.clc(); // throw away carry since it'll never be used + + calculate_status_flags(a, opsize, dst, FLAG_S | FLAG_Z); + } } else { - Label restore_flags = a.newLabel(); + Label calc = a.newLabel(); Label end = a.newLabel(); Gp shift = cl; a.mov(r10, rax); - a.seto(al); - a.movzx(r11, al); - a.lahf(); // no status flags should change if shift is 0, so preserve flags + a.lahf(); mov_reg_param(a, shift, param); a.and_(shift, opsize * 8 - 1); a.test(shift, shift); - a.short_().jz(restore_flags); - a.sahf(); // restore flags to keep carry for rolc/rorc - a.mov(rax, r10); + a.short_().jnz(calc); - a.emit(opcode, dst, shift); + a.mov(rax, r10); if (update_flags) - calculate_status_flags(a, opsize, dst, FLAG_S | FLAG_Z); // calculate status flags but preserve carry + a.clc(); // throw away carry since it'll never be used a.short_().jmp(end); - a.bind(restore_flags); - - // restore overflow flag - a.add(r11.r32(), 0x7fffffff); + a.bind(calc); - // restore other flags - a.sahf(); + a.sahf(); // restore flags to keep carry for rolc/rorc a.mov(rax, r10); + a.emit(opcode, dst, shift); + a.bind(end); + + if (update_flags) + calculate_status_flags(a, opsize, dst, FLAG_S | FLAG_Z); // calculate status flags but preserve carry } } diff --git a/src/devices/cpu/drcbex86.cpp b/src/devices/cpu/drcbex86.cpp index 19fc002949b..f97ef780468 100644 --- a/src/devices/cpu/drcbex86.cpp +++ b/src/devices/cpu/drcbex86.cpp @@ -1122,44 +1122,52 @@ void drcbe_x86::shift_op_param(Assembler &a, Inst::Id const opcode, size_t opsiz { if (param.is_immediate()) { - uint32_t bitshift = (param.immediate() & (opsize * 8 - 1)); + const uint32_t bitshift = param.immediate() & (opsize * 8 - 1); - if (optimize(a, dst, param) || bitshift == 0) - return; - - a.emit(opcode, dst, imm(bitshift)); + if (!optimize(a, dst, param) && bitshift != 0) + a.emit(opcode, dst, imm(bitshift)); if (update_flags) + { + if (bitshift == 0) + a.clc(); // throw away carry since it'll never be used + calculate_status_flags(a, dst, FLAG_S | FLAG_Z); // calculate status flags but preserve carry + } } else { - Label restore_flags = a.newLabel(); + Label calc = a.newLabel(); Label end = a.newLabel(); Gp shift = dst.as().id() == ecx.id() ? ebx : ecx; - a.pushfd(); // no status flags should change if shift is 0, so preserve flags + a.pushfd(); // preserve flags for carry emit_mov_r32_p32(a, shift, param); a.and_(shift, opsize * 8 - 1); a.test(shift, shift); - a.short_().jz(restore_flags); - a.popfd(); // restore flags to keep carry for rolc/rorc + a.short_().jnz(calc); - a.emit(opcode, dst, shift); + a.popfd(); // preserved flags not needed so throw it away if (update_flags) - calculate_status_flags(a, dst, FLAG_S | FLAG_Z); // calculate status flags but preserve carry + a.clc(); // throw away carry since it'll never be used a.short_().jmp(end); - a.bind(restore_flags); - a.popfd(); + a.bind(calc); + + a.popfd(); // restore flags to keep carry for rolc/rorc + + a.emit(opcode, dst, shift); a.bind(end); + + if (update_flags) + calculate_status_flags(a, dst, FLAG_S | FLAG_Z); // calculate status flags but preserve carry } } @@ -1552,8 +1560,6 @@ void drcbe_x86::emit_shl_r64_p64(Assembler &a, Gp const ®lo, Gp const ®hi, ;// skip else { - saveflags = saveflags && count > 0; - while (count >= 32) { if (inst.flags() != 0) @@ -1572,13 +1578,25 @@ void drcbe_x86::emit_shl_r64_p64(Assembler &a, Gp const ®lo, Gp const ®hi, if (inst.flags() != 0 || count > 0) { a.shld(reghi, reglo, count); // shld reghi,reglo,count - if (saveflags) a.pushfd(); // pushf + if (saveflags && count != 0) a.pushfd(); // pushf a.shl(reglo, count); // shl reglo,count } } if (saveflags) - emit_combine_z_shl_flags(a); + { + if (count == 0) + { + a.test(reglo, reglo); + a.pushfd(); + calculate_status_flags(a, reghi, FLAG_S | FLAG_Z); + emit_combine_z_flags(a); + } + else + { + emit_combine_z_shl_flags(a); + } + } } else { @@ -1587,8 +1605,6 @@ void drcbe_x86::emit_shl_r64_p64(Assembler &a, Gp const ®lo, Gp const ®hi, Label skip1 = a.newLabel(); Label skip2 = a.newLabel(); - a.pushfd(); - emit_mov_r32_p32(a, ecx, param); // mov ecx,param a.and_(ecx, 63); @@ -1622,14 +1638,21 @@ void drcbe_x86::emit_shl_r64_p64(Assembler &a, Gp const ®lo, Gp const ®hi, a.shl(reglo, cl); // shl reglo,cl if (saveflags) + { emit_combine_z_shl_flags(a); - a.lea(esp, ptr(esp, 4)); - - a.jmp(end); + a.short_().jmp(end); + } a.bind(skipall); - a.popfd(); + + if (saveflags) + { + a.test(reglo, reglo); + a.pushfd(); + calculate_status_flags(a, reghi, FLAG_S | FLAG_Z); + emit_combine_z_flags(a); + } a.bind(end); } @@ -1651,8 +1674,6 @@ void drcbe_x86::emit_shr_r64_p64(Assembler &a, Gp const ®lo, Gp const ®hi, ;// skip else { - saveflags = saveflags && count > 0; - while (count >= 32) { if (inst.flags() != 0) @@ -1671,22 +1692,32 @@ void drcbe_x86::emit_shr_r64_p64(Assembler &a, Gp const ®lo, Gp const ®hi, if (inst.flags() != 0 || count > 0) { a.shrd(reglo, reghi, count); // shrd reglo,reghi,count - if (saveflags) a.pushfd(); // pushf + if (saveflags && count != 0) a.pushfd(); // pushf a.shr(reghi, count); // shr reghi,count } } if (saveflags) { - // take carry from lower register's flags - a.pushfd(); - a.mov(ecx, dword_ptr(esp, 4)); - a.and_(ecx, 0x01); // carry flag - a.and_(dword_ptr(esp, 0), ~0x01); - a.or_(dword_ptr(esp, 0), ecx); - a.popfd(); + if (count == 0) + { + a.test(reglo, reglo); + a.pushfd(); + calculate_status_flags(a, reghi, FLAG_S | FLAG_Z); + emit_combine_z_flags(a); + } + else + { + // take carry from lower register's flags + a.pushfd(); + a.mov(ecx, dword_ptr(esp, 4)); + a.and_(ecx, 0x01); // carry flag + a.and_(dword_ptr(esp, 0), ~0x01); + a.or_(dword_ptr(esp, 0), ecx); + a.popfd(); - emit_combine_z_flags(a); + emit_combine_z_flags(a); + } } } else @@ -1696,8 +1727,6 @@ void drcbe_x86::emit_shr_r64_p64(Assembler &a, Gp const ®lo, Gp const ®hi, Label skip1 = a.newLabel(); Label skip2 = a.newLabel(); - a.pushfd(); - emit_mov_r32_p32(a, ecx, param); // mov ecx,param a.and_(ecx, 63); @@ -1741,14 +1770,19 @@ void drcbe_x86::emit_shr_r64_p64(Assembler &a, Gp const ®lo, Gp const ®hi, a.popfd(); emit_combine_z_flags(a); - } - - a.lea(esp, ptr(esp, 4)); - a.jmp(end); + a.short_().jmp(end); + } a.bind(skipall); - a.popfd(); + + if (saveflags) + { + a.test(reglo, reglo); + a.pushfd(); + calculate_status_flags(a, reghi, FLAG_S | FLAG_Z); + emit_combine_z_flags(a); + } a.bind(end); } @@ -1770,8 +1804,6 @@ void drcbe_x86::emit_sar_r64_p64(Assembler &a, Gp const ®lo, Gp const ®hi, ;// skip else { - saveflags = saveflags && count > 0; - while (count >= 32) { if (inst.flags() != 0) @@ -1790,32 +1822,40 @@ void drcbe_x86::emit_sar_r64_p64(Assembler &a, Gp const ®lo, Gp const ®hi, if (inst.flags() != 0 || count > 0) { a.shrd(reglo, reghi, count); // shrd reglo,reghi,count - if (saveflags) a.pushfd(); // pushf + if (saveflags && count != 0) a.pushfd(); // pushf a.sar(reghi, count); // sar reghi,count } } if (saveflags) { - // take carry from lower register's flags - a.pushfd(); - a.mov(ecx, dword_ptr(esp, 4)); - a.and_(ecx, 0x01); // carry flag - a.and_(dword_ptr(esp, 0), ~0x01); - a.or_(dword_ptr(esp, 0), ecx); - a.popfd(); + if (count == 0) + { + a.test(reglo, reglo); + a.pushfd(); + calculate_status_flags(a, reghi, FLAG_S | FLAG_Z); + emit_combine_z_flags(a); + } + else + { + // take carry from lower register's flags + a.pushfd(); + a.mov(ecx, dword_ptr(esp, 4)); + a.and_(ecx, 0x01); // carry flag + a.and_(dword_ptr(esp, 0), ~0x01); + a.or_(dword_ptr(esp, 0), ecx); + a.popfd(); - emit_combine_z_flags(a); + emit_combine_z_flags(a); + } } } else { - Label skipall = a.newLabel(); - Label end = a.newLabel(); Label skip1 = a.newLabel(); Label skip2 = a.newLabel(); - - a.pushfd(); + Label skipall = a.newLabel(); + Label end = a.newLabel(); emit_mov_r32_p32(a, ecx, param); // mov ecx,param @@ -1860,14 +1900,19 @@ void drcbe_x86::emit_sar_r64_p64(Assembler &a, Gp const ®lo, Gp const ®hi, a.popfd(); emit_combine_z_flags(a); - } - a.lea(esp, ptr(esp, 4)); - - a.jmp(end); + a.short_().jmp(end); + } a.bind(skipall); - a.popfd(); + + if (saveflags) + { + a.test(reglo, reglo); + a.pushfd(); + calculate_status_flags(a, reghi, FLAG_S | FLAG_Z); + emit_combine_z_flags(a); + } a.bind(end); } @@ -1893,8 +1938,6 @@ void drcbe_x86::emit_rol_r64_p64(Assembler &a, Gp const ®lo, Gp const ®hi, ;// skip else { - saveflags = saveflags && count > 0; - while (count >= 32) { if (inst.flags() != 0) @@ -1913,24 +1956,34 @@ void drcbe_x86::emit_rol_r64_p64(Assembler &a, Gp const ®lo, Gp const ®hi, a.mov(ecx, reglo); a.shld(reglo, reghi, count); - if (saveflags) a.pushfd(); + if (saveflags && count != 0) a.pushfd(); a.shld(reghi, ecx, count); } if (saveflags) - emit_combine_zs_flags(a); + { + if (count == 0) + { + a.test(reglo, reglo); + a.pushfd(); + calculate_status_flags(a, reghi, FLAG_S | FLAG_Z); + emit_combine_z_flags(a); + } + else + { + emit_combine_zs_flags(a); + } + } } else { - Label end = a.newLabel(); Label skipall = a.newLabel(); + Label end = a.newLabel(); Label skip1 = a.newLabel(); Label shift_loop = a.newLabel(); emit_mov_r32_p32(a, ecx, param); - a.pushfd(); - a.and_(ecx, 63); a.test(ecx, ecx); a.short_().jz(skipall); @@ -1956,20 +2009,26 @@ void drcbe_x86::emit_rol_r64_p64(Assembler &a, Gp const ®lo, Gp const ®hi, a.bind(skip1); reset_last_upper_lower_reg(); - a.mov(tempreg, reglo); a.shld(reglo, reghi, cl); if (saveflags) a.pushfd(); a.shld(reghi, tempreg, cl); if (saveflags) + { emit_combine_zs_flags(a); - - a.lea(esp, ptr(esp, 4)); - a.jmp(end); + a.short_().jmp(end); + } a.bind(skipall); - a.popfd(); + + if (saveflags) + { + a.test(reglo, reglo); + a.pushfd(); + calculate_status_flags(a, reghi, FLAG_S | FLAG_Z); + emit_combine_z_flags(a); + } a.bind(end); } @@ -1997,8 +2056,6 @@ void drcbe_x86::emit_ror_r64_p64(Assembler &a, Gp const ®lo, Gp const ®hi, ;// skip else { - saveflags = saveflags && count > 0; - while (count >= 32) { if (inst.flags() != 0) @@ -2017,24 +2074,34 @@ void drcbe_x86::emit_ror_r64_p64(Assembler &a, Gp const ®lo, Gp const ®hi, a.mov(tempreg, reghi); a.shrd(reghi, reglo, count); - if (saveflags) a.pushfd(); + if (saveflags && count != 0) a.pushfd(); a.shrd(reglo, tempreg, count); if (saveflags) - emit_combine_zs_flags(a); + { + if (count == 0) + { + a.test(reglo, reglo); + a.pushfd(); + calculate_status_flags(a, reghi, FLAG_S | FLAG_Z); + emit_combine_z_flags(a); + } + else + { + emit_combine_zs_flags(a); + } + } } } else { - Label end = a.newLabel(); Label skipall = a.newLabel(); + Label end = a.newLabel(); Label skip1 = a.newLabel(); Label shift_loop = a.newLabel(); emit_mov_r32_p32(a, ecx, param); - a.pushfd(); - a.and_(ecx, 63); a.test(ecx, ecx); a.short_().jz(skipall); @@ -2060,20 +2127,26 @@ void drcbe_x86::emit_ror_r64_p64(Assembler &a, Gp const ®lo, Gp const ®hi, a.bind(skip1); reset_last_upper_lower_reg(); - a.mov(tempreg, reghi); a.shrd(reghi, reglo, cl); if (saveflags) a.pushfd(); a.shrd(reglo, tempreg, cl); if (saveflags) + { emit_combine_zs_flags(a); - - a.lea(esp, ptr(esp, 4)); - a.jmp(end); + a.short_().jmp(end); + } a.bind(skipall); - a.popfd(); + + if (saveflags) + { + a.test(reglo, reglo); + a.pushfd(); + calculate_status_flags(a, reghi, FLAG_S | FLAG_Z); + emit_combine_z_flags(a); + } a.bind(end); } @@ -2092,6 +2165,7 @@ void drcbe_x86::emit_rcl_r64_p64(Assembler &a, Gp const ®lo, Gp const ®hi, Label loop = a.newLabel(); Label skipall = a.newLabel(); Label skiploop = a.newLabel(); + Label end = a.newLabel(); a.pushfd(); // keep carry flag after and emit_mov_r32_p32_keepflags(a, ecx, param); @@ -2107,7 +2181,7 @@ void drcbe_x86::emit_rcl_r64_p64(Assembler &a, Gp const ®lo, Gp const ®hi, a.lea(ecx, ptr(ecx, -1)); a.rcl(reglo, 1); a.rcl(reghi, 1); - a.jmp(loop); + a.short_().jmp(loop); a.bind(skiploop); reset_last_upper_lower_reg(); @@ -2120,9 +2194,21 @@ void drcbe_x86::emit_rcl_r64_p64(Assembler &a, Gp const ®lo, Gp const ®hi, a.pushfd(); calculate_status_flags(a, reghi, FLAG_S | FLAG_Z); emit_combine_z_flags(a); + + a.short_().jmp(end); } a.bind(skipall); + + if (inst.flags()) + { + a.test(reglo, reglo); + a.pushfd(); + calculate_status_flags(a, reghi, FLAG_S | FLAG_Z); + emit_combine_z_flags(a); + } + + a.bind(end); reset_last_upper_lower_reg(); } @@ -2137,6 +2223,7 @@ void drcbe_x86::emit_rcr_r64_p64(Assembler &a, Gp const ®lo, Gp const ®hi, Label loop = a.newLabel(); Label skipall = a.newLabel(); Label skiploop = a.newLabel(); + Label end = a.newLabel(); a.pushfd(); // keep carry flag after and emit_mov_r32_p32_keepflags(a, ecx, param); @@ -2152,7 +2239,7 @@ void drcbe_x86::emit_rcr_r64_p64(Assembler &a, Gp const ®lo, Gp const ®hi, a.lea(ecx, ptr(ecx, -1)); a.rcr(reghi, 1); a.rcr(reglo, 1); - a.jmp(loop); + a.short_().jmp(loop); a.bind(skiploop); reset_last_upper_lower_reg(); @@ -2165,9 +2252,20 @@ void drcbe_x86::emit_rcr_r64_p64(Assembler &a, Gp const ®lo, Gp const ®hi, a.pushfd(); calculate_status_flags(a, reghi, FLAG_S | FLAG_Z); emit_combine_z_flags(a); + + a.short_().jmp(end); } a.bind(skipall); + if (inst.flags()) + { + a.test(reglo, reglo); + a.pushfd(); + calculate_status_flags(a, reghi, FLAG_S | FLAG_Z); + emit_combine_z_flags(a); + } + + a.bind(end); reset_last_upper_lower_reg(); } @@ -3614,7 +3712,7 @@ void drcbe_x86::op_carry(Assembler &a, const instruction &inst) if (bitp.is_immediate()) { - uint32_t bitshift = (bitp.immediate() & (inst.size() * 8 - 1)); + const uint32_t bitshift = bitp.immediate() & (inst.size() * 8 - 1); if (bitshift < 32) { if (srcp.is_memory()) @@ -5335,7 +5433,7 @@ void drcbe_x86::op_lzcnt(Assembler &a, const instruction &inst) a.jz(skip); a.xor_(edx, 31 ^ 63); a.mov(dstreg, edx); - a.jmp(end); + a.short_().jmp(end); a.bind(skip); a.mov(edx, 64 ^ 63); @@ -6610,9 +6708,9 @@ int drcbe_x86::dmulu(uint64_t &dstlo, uint64_t &dsthi, uint64_t src1, uint64_t s dstlo = lo; if (halfmul_flags) - return ((lo >> 60) & FLAG_S) | ((hi != 0) << 1); + return ((lo >> 60) & FLAG_S) | ((hi != 0) << 1) | ((dstlo == 0) << 2); - return ((hi >> 60) & FLAG_S) | ((hi != 0) << 1); + return ((hi >> 60) & FLAG_S) | ((hi != 0) << 1) | ((dsthi == 0 && dstlo == 0) << 2); } @@ -6668,9 +6766,9 @@ int drcbe_x86::dmuls(uint64_t &dstlo, uint64_t &dsthi, int64_t src1, int64_t src dstlo = lo; if (halfmul_flags) - return ((lo >> 60) & FLAG_S) | ((hi != ((int64_t)lo >> 63)) << 1); + return ((lo >> 60) & FLAG_S) | ((hi != ((int64_t)lo >> 63)) << 1) | ((dstlo == 0) << 2); - return ((hi >> 60) & FLAG_S) | ((hi != ((int64_t)lo >> 63)) << 1); + return ((hi >> 60) & FLAG_S) | ((hi != ((int64_t)lo >> 63)) << 1) | ((dsthi == 0 && dstlo == 0) << 2); } -- cgit v1.2.3