diff --git a/src/dynarmic/backend/x64/a32_emit_x64.cpp b/src/dynarmic/backend/x64/a32_emit_x64.cpp index 05da3601..f579865e 100644 --- a/src/dynarmic/backend/x64/a32_emit_x64.cpp +++ b/src/dynarmic/backend/x64/a32_emit_x64.cpp @@ -541,6 +541,37 @@ void A32EmitX64::EmitA32SetCpsrNZCVQ(A32EmitContext& ctx, IR::Inst* inst) { } } +void A32EmitX64::EmitA32SetCpsrNZ(A32EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + + ctx.reg_alloc.Use(args[0], HostLoc::RAX); + + code.mov(al, code.byte[r15 + offsetof(A32JitState, cpsr_nzcv) + 1]); + code.and_(al, 1); + code.or_(al, ah); + code.mov(code.byte[r15 + offsetof(A32JitState, cpsr_nzcv) + 1], al); +} + +void A32EmitX64::EmitA32SetCpsrNZC(A32EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + + ctx.reg_alloc.Use(args[0], HostLoc::RAX); + + if (args[1].IsImmediate()) { + const bool c = args[1].GetImmediateU1(); + + code.mov(al, ah); + code.or_(al, c); + code.mov(code.byte[r15 + offsetof(A32JitState, cpsr_nzcv) + 1], al); + } else { + const Xbyak::Reg8 c = ctx.reg_alloc.UseGpr(args[1]).cvt8(); + + code.mov(al, ah); + code.or_(al, c); + code.mov(code.byte[r15 + offsetof(A32JitState, cpsr_nzcv) + 1], al); + } +} + static void EmitGetFlag(BlockOfCode& code, A32EmitContext& ctx, IR::Inst* inst, size_t flag_bit) { const Xbyak::Reg32 result = ctx.reg_alloc.ScratchGpr().cvt32(); code.mov(result, dword[r15 + offsetof(A32JitState, cpsr_nzcv)]); @@ -551,48 +582,10 @@ static void EmitGetFlag(BlockOfCode& code, A32EmitContext& ctx, IR::Inst* inst, ctx.reg_alloc.DefineValue(inst, result); } -static void EmitSetFlag(BlockOfCode& code, A32EmitContext& ctx, IR::Inst* inst, size_t flag_bit) { - const u32 flag_mask = 1u << flag_bit; - auto args = ctx.reg_alloc.GetArgumentInfo(inst); - if (args[0].IsImmediate()) { - if (args[0].GetImmediateU1()) { - code.or_(dword[r15 + offsetof(A32JitState, cpsr_nzcv)], flag_mask); - } else { - code.and_(dword[r15 + offsetof(A32JitState, cpsr_nzcv)], ~flag_mask); - } - } else { - const Xbyak::Reg32 to_store = ctx.reg_alloc.UseScratchGpr(args[0]).cvt32(); - - if (flag_bit != 0) { - code.shl(to_store, static_cast(flag_bit)); - code.and_(dword[r15 + offsetof(A32JitState, cpsr_nzcv)], ~flag_mask); - code.or_(dword[r15 + offsetof(A32JitState, cpsr_nzcv)], to_store); - } else { - code.mov(code.byte[r15 + offsetof(A32JitState, cpsr_nzcv)], to_store.cvt8()); - } - } -} - -void A32EmitX64::EmitA32SetNFlag(A32EmitContext& ctx, IR::Inst* inst) { - EmitSetFlag(code, ctx, inst, NZCV::x64_n_flag_bit); -} - -void A32EmitX64::EmitA32SetZFlag(A32EmitContext& ctx, IR::Inst* inst) { - EmitSetFlag(code, ctx, inst, NZCV::x64_z_flag_bit); -} - void A32EmitX64::EmitA32GetCFlag(A32EmitContext& ctx, IR::Inst* inst) { EmitGetFlag(code, ctx, inst, NZCV::x64_c_flag_bit); } -void A32EmitX64::EmitA32SetCFlag(A32EmitContext& ctx, IR::Inst* inst) { - EmitSetFlag(code, ctx, inst, NZCV::x64_c_flag_bit); -} - -void A32EmitX64::EmitA32SetVFlag(A32EmitContext& ctx, IR::Inst* inst) { - EmitSetFlag(code, ctx, inst, NZCV::x64_v_flag_bit); -} - void A32EmitX64::EmitA32OrQFlag(A32EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); if (args[0].IsImmediate()) { diff --git a/src/dynarmic/backend/x64/emit_x64.cpp b/src/dynarmic/backend/x64/emit_x64.cpp index 5ffeefc1..286f58c5 100644 --- a/src/dynarmic/backend/x64/emit_x64.cpp +++ b/src/dynarmic/backend/x64/emit_x64.cpp @@ -134,6 +134,31 @@ void EmitX64::EmitGetLowerFromOp(EmitContext&, IR::Inst*) { ASSERT_MSG(false, "should never happen"); } +void EmitX64::EmitGetNZFromOp(EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + + const int bitsize = [&] { + switch (args[0].GetType()) { + case IR::Type::U8: + return 8; + case IR::Type::U16: + return 16; + case IR::Type::U32: + return 32; + case IR::Type::U64: + return 64; + default: + UNREACHABLE(); + } + }(); + + const Xbyak::Reg64 nz = ctx.reg_alloc.ScratchGpr(HostLoc::RAX); + const Xbyak::Reg value = ctx.reg_alloc.UseGpr(args[0]).changeBit(bitsize); + code.cmp(value, 0); + code.lahf(); + ctx.reg_alloc.DefineValue(inst, nz); +} + void EmitX64::EmitGetNZCVFromOp(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); diff --git a/src/dynarmic/frontend/A32/a32_ir_emitter.cpp b/src/dynarmic/frontend/A32/a32_ir_emitter.cpp index 7f686b32..343e521a 100644 --- a/src/dynarmic/frontend/A32/a32_ir_emitter.cpp +++ b/src/dynarmic/frontend/A32/a32_ir_emitter.cpp @@ -166,22 +166,6 @@ IR::U1 IREmitter::GetCFlag() { return Inst(Opcode::A32GetCFlag); } -void IREmitter::SetNFlag(const IR::U1& value) { - Inst(Opcode::A32SetNFlag, value); -} - -void IREmitter::SetZFlag(const IR::U1& value) { - Inst(Opcode::A32SetZFlag, value); -} - -void IREmitter::SetCFlag(const IR::U1& value) { - Inst(Opcode::A32SetCFlag, value); -} - -void IREmitter::SetVFlag(const IR::U1& value) { - Inst(Opcode::A32SetVFlag, value); -} - void IREmitter::OrQFlag(const IR::U1& value) { Inst(Opcode::A32OrQFlag, value); } @@ -198,6 +182,18 @@ void IREmitter::SetGEFlagsCompressed(const IR::U32& value) { Inst(Opcode::A32SetGEFlagsCompressed, value); } +IR::NZCV IREmitter::NZFrom(const IR::Value& value) { + return Inst(Opcode::GetNZFromOp, value); +} + +void IREmitter::SetCpsrNZ(const IR::NZCV& nz) { + Inst(Opcode::A32SetCpsrNZ, nz); +} + +void IREmitter::SetCpsrNZC(const IR::NZCV& nz, const IR::U1& c) { + Inst(Opcode::A32SetCpsrNZC, nz, c); +} + void IREmitter::DataSynchronizationBarrier() { Inst(Opcode::A32DataSynchronizationBarrier); } diff --git a/src/dynarmic/frontend/A32/a32_ir_emitter.h b/src/dynarmic/frontend/A32/a32_ir_emitter.h index 96d162b0..9fde4f87 100644 --- a/src/dynarmic/frontend/A32/a32_ir_emitter.h +++ b/src/dynarmic/frontend/A32/a32_ir_emitter.h @@ -62,15 +62,15 @@ public: void SetCheckBit(const IR::U1& value); IR::U1 GetOverflowFrom(const IR::Value& value); IR::U1 GetCFlag(); - void SetNFlag(const IR::U1& value); - void SetZFlag(const IR::U1& value); - void SetCFlag(const IR::U1& value); - void SetVFlag(const IR::U1& value); void OrQFlag(const IR::U1& value); IR::U32 GetGEFlags(); void SetGEFlags(const IR::U32& value); void SetGEFlagsCompressed(const IR::U32& value); + IR::NZCV NZFrom(const IR::Value& value); + void SetCpsrNZ(const IR::NZCV& nz); + void SetCpsrNZC(const IR::NZCV& nz, const IR::U1& c); + void DataSynchronizationBarrier(); void DataMemoryBarrier(); void InstructionSynchronizationBarrier(); diff --git a/src/dynarmic/frontend/A32/translate/impl/data_processing.cpp b/src/dynarmic/frontend/A32/translate/impl/data_processing.cpp index 69d0a946..9d7ea6a1 100644 --- a/src/dynarmic/frontend/A32/translate/impl/data_processing.cpp +++ b/src/dynarmic/frontend/A32/translate/impl/data_processing.cpp @@ -181,9 +181,7 @@ bool TranslatorVisitor::arm_AND_imm(Cond cond, bool S, Reg n, Reg d, int rotate, ir.SetRegister(d, result); if (S) { - ir.SetNFlag(ir.MostSignificantBit(result)); - ir.SetZFlag(ir.IsZero(result)); - ir.SetCFlag(imm_carry.carry); + ir.SetCpsrNZC(ir.NZFrom(result), imm_carry.carry); } return true; @@ -210,9 +208,7 @@ bool TranslatorVisitor::arm_AND_reg(Cond cond, bool S, Reg n, Reg d, Imm<5> imm5 } ir.SetRegister(d, result); if (S) { - ir.SetNFlag(ir.MostSignificantBit(result)); - ir.SetZFlag(ir.IsZero(result)); - ir.SetCFlag(shifted.carry); + ir.SetCpsrNZC(ir.NZFrom(result), shifted.carry); } return true; @@ -235,9 +231,7 @@ bool TranslatorVisitor::arm_AND_rsr(Cond cond, bool S, Reg n, Reg d, Reg s, Shif ir.SetRegister(d, result); if (S) { - ir.SetNFlag(ir.MostSignificantBit(result)); - ir.SetZFlag(ir.IsZero(result)); - ir.SetCFlag(shifted.carry); + ir.SetCpsrNZC(ir.NZFrom(result), shifted.carry); } return true; @@ -264,9 +258,7 @@ bool TranslatorVisitor::arm_BIC_imm(Cond cond, bool S, Reg n, Reg d, int rotate, ir.SetRegister(d, result); if (S) { - ir.SetNFlag(ir.MostSignificantBit(result)); - ir.SetZFlag(ir.IsZero(result)); - ir.SetCFlag(imm_carry.carry); + ir.SetCpsrNZC(ir.NZFrom(result), imm_carry.carry); } return true; @@ -294,9 +286,7 @@ bool TranslatorVisitor::arm_BIC_reg(Cond cond, bool S, Reg n, Reg d, Imm<5> imm5 ir.SetRegister(d, result); if (S) { - ir.SetNFlag(ir.MostSignificantBit(result)); - ir.SetZFlag(ir.IsZero(result)); - ir.SetCFlag(shifted.carry); + ir.SetCpsrNZC(ir.NZFrom(result), shifted.carry); } return true; @@ -319,9 +309,7 @@ bool TranslatorVisitor::arm_BIC_rsr(Cond cond, bool S, Reg n, Reg d, Reg s, Shif ir.SetRegister(d, result); if (S) { - ir.SetNFlag(ir.MostSignificantBit(result)); - ir.SetZFlag(ir.IsZero(result)); - ir.SetCFlag(shifted.carry); + ir.SetCpsrNZC(ir.NZFrom(result), shifted.carry); } return true; @@ -438,9 +426,7 @@ bool TranslatorVisitor::arm_EOR_imm(Cond cond, bool S, Reg n, Reg d, int rotate, ir.SetRegister(d, result); if (S) { - ir.SetNFlag(ir.MostSignificantBit(result)); - ir.SetZFlag(ir.IsZero(result)); - ir.SetCFlag(imm_carry.carry); + ir.SetCpsrNZC(ir.NZFrom(result), imm_carry.carry); } return true; @@ -468,9 +454,7 @@ bool TranslatorVisitor::arm_EOR_reg(Cond cond, bool S, Reg n, Reg d, Imm<5> imm5 ir.SetRegister(d, result); if (S) { - ir.SetNFlag(ir.MostSignificantBit(result)); - ir.SetZFlag(ir.IsZero(result)); - ir.SetCFlag(shifted.carry); + ir.SetCpsrNZC(ir.NZFrom(result), shifted.carry); } return true; @@ -493,9 +477,7 @@ bool TranslatorVisitor::arm_EOR_rsr(Cond cond, bool S, Reg n, Reg d, Reg s, Shif ir.SetRegister(d, result); if (S) { - ir.SetNFlag(ir.MostSignificantBit(result)); - ir.SetZFlag(ir.IsZero(result)); - ir.SetCFlag(shifted.carry); + ir.SetCpsrNZC(ir.NZFrom(result), shifted.carry); } return true; @@ -522,9 +504,7 @@ bool TranslatorVisitor::arm_MOV_imm(Cond cond, bool S, Reg d, int rotate, Imm<8> ir.SetRegister(d, result); if (S) { - ir.SetNFlag(ir.MostSignificantBit(result)); - ir.SetZFlag(ir.IsZero(result)); - ir.SetCFlag(imm_carry.carry); + ir.SetCpsrNZC(ir.NZFrom(result), imm_carry.carry); } return true; @@ -552,9 +532,7 @@ bool TranslatorVisitor::arm_MOV_reg(Cond cond, bool S, Reg d, Imm<5> imm5, Shift ir.SetRegister(d, result); if (S) { - ir.SetNFlag(ir.MostSignificantBit(result)); - ir.SetZFlag(ir.IsZero(result)); - ir.SetCFlag(shifted.carry); + ir.SetCpsrNZC(ir.NZFrom(result), shifted.carry); } return true; @@ -575,9 +553,7 @@ bool TranslatorVisitor::arm_MOV_rsr(Cond cond, bool S, Reg d, Reg s, ShiftType s const auto result = shifted.result; ir.SetRegister(d, result); if (S) { - ir.SetNFlag(ir.MostSignificantBit(result)); - ir.SetZFlag(ir.IsZero(result)); - ir.SetCFlag(shifted.carry); + ir.SetCpsrNZC(ir.NZFrom(result), shifted.carry); } return true; @@ -604,9 +580,7 @@ bool TranslatorVisitor::arm_MVN_imm(Cond cond, bool S, Reg d, int rotate, Imm<8> ir.SetRegister(d, result); if (S) { - ir.SetNFlag(ir.MostSignificantBit(result)); - ir.SetZFlag(ir.IsZero(result)); - ir.SetCFlag(imm_carry.carry); + ir.SetCpsrNZC(ir.NZFrom(result), imm_carry.carry); } return true; @@ -634,9 +608,7 @@ bool TranslatorVisitor::arm_MVN_reg(Cond cond, bool S, Reg d, Imm<5> imm5, Shift ir.SetRegister(d, result); if (S) { - ir.SetNFlag(ir.MostSignificantBit(result)); - ir.SetZFlag(ir.IsZero(result)); - ir.SetCFlag(shifted.carry); + ir.SetCpsrNZC(ir.NZFrom(result), shifted.carry); } return true; @@ -659,9 +631,7 @@ bool TranslatorVisitor::arm_MVN_rsr(Cond cond, bool S, Reg d, Reg s, ShiftType s ir.SetRegister(d, result); if (S) { - ir.SetNFlag(ir.MostSignificantBit(result)); - ir.SetZFlag(ir.IsZero(result)); - ir.SetCFlag(shifted.carry); + ir.SetCpsrNZC(ir.NZFrom(result), shifted.carry); } return true; @@ -688,9 +658,7 @@ bool TranslatorVisitor::arm_ORR_imm(Cond cond, bool S, Reg n, Reg d, int rotate, ir.SetRegister(d, result); if (S) { - ir.SetNFlag(ir.MostSignificantBit(result)); - ir.SetZFlag(ir.IsZero(result)); - ir.SetCFlag(imm_carry.carry); + ir.SetCpsrNZC(ir.NZFrom(result), imm_carry.carry); } return true; @@ -718,9 +686,7 @@ bool TranslatorVisitor::arm_ORR_reg(Cond cond, bool S, Reg n, Reg d, Imm<5> imm5 ir.SetRegister(d, result); if (S) { - ir.SetNFlag(ir.MostSignificantBit(result)); - ir.SetZFlag(ir.IsZero(result)); - ir.SetCFlag(shifted.carry); + ir.SetCpsrNZC(ir.NZFrom(result), shifted.carry); } return true; @@ -743,9 +709,7 @@ bool TranslatorVisitor::arm_ORR_rsr(Cond cond, bool S, Reg n, Reg d, Reg s, Shif ir.SetRegister(d, result); if (S) { - ir.SetNFlag(ir.MostSignificantBit(result)); - ir.SetZFlag(ir.IsZero(result)); - ir.SetCFlag(shifted.carry); + ir.SetCpsrNZC(ir.NZFrom(result), shifted.carry); } return true; @@ -1066,9 +1030,7 @@ bool TranslatorVisitor::arm_TEQ_imm(Cond cond, Reg n, int rotate, Imm<8> imm8) { const auto imm_carry = ArmExpandImm_C(rotate, imm8, ir.GetCFlag()); const auto result = ir.Eor(ir.GetRegister(n), ir.Imm32(imm_carry.imm32)); - ir.SetNFlag(ir.MostSignificantBit(result)); - ir.SetZFlag(ir.IsZero(result)); - ir.SetCFlag(imm_carry.carry); + ir.SetCpsrNZC(ir.NZFrom(result), imm_carry.carry); return true; } @@ -1082,9 +1044,7 @@ bool TranslatorVisitor::arm_TEQ_reg(Cond cond, Reg n, Imm<5> imm5, ShiftType shi const auto shifted = EmitImmShift(ir.GetRegister(m), shift, imm5, carry_in); const auto result = ir.Eor(ir.GetRegister(n), shifted.result); - ir.SetNFlag(ir.MostSignificantBit(result)); - ir.SetZFlag(ir.IsZero(result)); - ir.SetCFlag(shifted.carry); + ir.SetCpsrNZC(ir.NZFrom(result), shifted.carry); return true; } @@ -1103,9 +1063,7 @@ bool TranslatorVisitor::arm_TEQ_rsr(Cond cond, Reg n, Reg s, ShiftType shift, Re const auto shifted = EmitRegShift(ir.GetRegister(m), shift, shift_n, carry_in); const auto result = ir.Eor(ir.GetRegister(n), shifted.result); - ir.SetNFlag(ir.MostSignificantBit(result)); - ir.SetZFlag(ir.IsZero(result)); - ir.SetCFlag(shifted.carry); + ir.SetCpsrNZC(ir.NZFrom(result), shifted.carry); return true; } @@ -1118,9 +1076,7 @@ bool TranslatorVisitor::arm_TST_imm(Cond cond, Reg n, int rotate, Imm<8> imm8) { const auto imm_carry = ArmExpandImm_C(rotate, imm8, ir.GetCFlag()); const auto result = ir.And(ir.GetRegister(n), ir.Imm32(imm_carry.imm32)); - ir.SetNFlag(ir.MostSignificantBit(result)); - ir.SetZFlag(ir.IsZero(result)); - ir.SetCFlag(imm_carry.carry); + ir.SetCpsrNZC(ir.NZFrom(result), imm_carry.carry); return true; } @@ -1134,9 +1090,7 @@ bool TranslatorVisitor::arm_TST_reg(Cond cond, Reg n, Imm<5> imm5, ShiftType shi const auto shifted = EmitImmShift(ir.GetRegister(m), shift, imm5, carry_in); const auto result = ir.And(ir.GetRegister(n), shifted.result); - ir.SetNFlag(ir.MostSignificantBit(result)); - ir.SetZFlag(ir.IsZero(result)); - ir.SetCFlag(shifted.carry); + ir.SetCpsrNZC(ir.NZFrom(result), shifted.carry); return true; } @@ -1155,9 +1109,7 @@ bool TranslatorVisitor::arm_TST_rsr(Cond cond, Reg n, Reg s, ShiftType shift, Re const auto shifted = EmitRegShift(ir.GetRegister(m), shift, shift_n, carry_in); const auto result = ir.And(ir.GetRegister(n), shifted.result); - ir.SetNFlag(ir.MostSignificantBit(result)); - ir.SetZFlag(ir.IsZero(result)); - ir.SetCFlag(shifted.carry); + ir.SetCpsrNZC(ir.NZFrom(result), shifted.carry); return true; } diff --git a/src/dynarmic/frontend/A32/translate/impl/multiply.cpp b/src/dynarmic/frontend/A32/translate/impl/multiply.cpp index adcf6ddb..2bda56a9 100644 --- a/src/dynarmic/frontend/A32/translate/impl/multiply.cpp +++ b/src/dynarmic/frontend/A32/translate/impl/multiply.cpp @@ -20,8 +20,7 @@ bool TranslatorVisitor::arm_MLA(Cond cond, bool S, Reg d, Reg a, Reg m, Reg n) { const auto result = ir.Add(ir.Mul(ir.GetRegister(n), ir.GetRegister(m)), ir.GetRegister(a)); ir.SetRegister(d, result); if (S) { - ir.SetNFlag(ir.MostSignificantBit(result)); - ir.SetZFlag(ir.IsZero(result)); + ir.SetCpsrNZ(ir.NZFrom(result)); } return true; @@ -59,8 +58,7 @@ bool TranslatorVisitor::arm_MUL(Cond cond, bool S, Reg d, Reg m, Reg n) { const auto result = ir.Mul(ir.GetRegister(n), ir.GetRegister(m)); ir.SetRegister(d, result); if (S) { - ir.SetNFlag(ir.MostSignificantBit(result)); - ir.SetZFlag(ir.IsZero(result)); + ir.SetCpsrNZ(ir.NZFrom(result)); } return true; @@ -91,8 +89,7 @@ bool TranslatorVisitor::arm_SMLAL(Cond cond, bool S, Reg dHi, Reg dLo, Reg m, Re ir.SetRegister(dLo, lo); ir.SetRegister(dHi, hi); if (S) { - ir.SetNFlag(ir.MostSignificantBit(hi)); - ir.SetZFlag(ir.IsZero(result)); + ir.SetCpsrNZ(ir.NZFrom(result)); } return true; @@ -121,8 +118,7 @@ bool TranslatorVisitor::arm_SMULL(Cond cond, bool S, Reg dHi, Reg dLo, Reg m, Re ir.SetRegister(dLo, lo); ir.SetRegister(dHi, hi); if (S) { - ir.SetNFlag(ir.MostSignificantBit(hi)); - ir.SetZFlag(ir.IsZero(result)); + ir.SetCpsrNZ(ir.NZFrom(result)); } return true; @@ -177,8 +173,7 @@ bool TranslatorVisitor::arm_UMLAL(Cond cond, bool S, Reg dHi, Reg dLo, Reg m, Re ir.SetRegister(dLo, lo); ir.SetRegister(dHi, hi); if (S) { - ir.SetNFlag(ir.MostSignificantBit(hi)); - ir.SetZFlag(ir.IsZero(result)); + ir.SetCpsrNZ(ir.NZFrom(result)); } return true; @@ -207,8 +202,7 @@ bool TranslatorVisitor::arm_UMULL(Cond cond, bool S, Reg dHi, Reg dLo, Reg m, Re ir.SetRegister(dLo, lo); ir.SetRegister(dHi, hi); if (S) { - ir.SetNFlag(ir.MostSignificantBit(hi)); - ir.SetZFlag(ir.IsZero(result)); + ir.SetCpsrNZ(ir.NZFrom(result)); } return true; diff --git a/src/dynarmic/frontend/A32/translate/impl/thumb16.cpp b/src/dynarmic/frontend/A32/translate/impl/thumb16.cpp index 0c531e9f..67a94a0e 100644 --- a/src/dynarmic/frontend/A32/translate/impl/thumb16.cpp +++ b/src/dynarmic/frontend/A32/translate/impl/thumb16.cpp @@ -22,9 +22,7 @@ bool TranslatorVisitor::thumb16_LSL_imm(Imm<5> imm5, Reg m, Reg d) { ir.SetRegister(d, result.result); if (!ir.current_location.IT().IsInITBlock()) { - ir.SetNFlag(ir.MostSignificantBit(result.result)); - ir.SetZFlag(ir.IsZero(result.result)); - ir.SetCFlag(result.carry); + ir.SetCpsrNZC(ir.NZFrom(result.result), result.carry); } return true; } @@ -37,9 +35,7 @@ bool TranslatorVisitor::thumb16_LSR_imm(Imm<5> imm5, Reg m, Reg d) { ir.SetRegister(d, result.result); if (!ir.current_location.IT().IsInITBlock()) { - ir.SetNFlag(ir.MostSignificantBit(result.result)); - ir.SetZFlag(ir.IsZero(result.result)); - ir.SetCFlag(result.carry); + ir.SetCpsrNZC(ir.NZFrom(result.result), result.carry); } return true; } @@ -52,9 +48,7 @@ bool TranslatorVisitor::thumb16_ASR_imm(Imm<5> imm5, Reg m, Reg d) { ir.SetRegister(d, result.result); if (!ir.current_location.IT().IsInITBlock()) { - ir.SetNFlag(ir.MostSignificantBit(result.result)); - ir.SetZFlag(ir.IsZero(result.result)); - ir.SetCFlag(result.carry); + ir.SetCpsrNZC(ir.NZFrom(result.result), result.carry); } return true; } @@ -117,8 +111,7 @@ bool TranslatorVisitor::thumb16_MOV_imm(Reg d, Imm<8> imm8) { ir.SetRegister(d, result); if (!ir.current_location.IT().IsInITBlock()) { - ir.SetNFlag(ir.MostSignificantBit(result)); - ir.SetZFlag(ir.IsZero(result)); + ir.SetCpsrNZ(ir.NZFrom(result)); } return true; } @@ -171,8 +164,7 @@ bool TranslatorVisitor::thumb16_AND_reg(Reg m, Reg d_n) { ir.SetRegister(d, result); if (!ir.current_location.IT().IsInITBlock()) { - ir.SetNFlag(ir.MostSignificantBit(result)); - ir.SetZFlag(ir.IsZero(result)); + ir.SetCpsrNZ(ir.NZFrom(result)); } return true; } @@ -186,8 +178,7 @@ bool TranslatorVisitor::thumb16_EOR_reg(Reg m, Reg d_n) { ir.SetRegister(d, result); if (!ir.current_location.IT().IsInITBlock()) { - ir.SetNFlag(ir.MostSignificantBit(result)); - ir.SetZFlag(ir.IsZero(result)); + ir.SetCpsrNZ(ir.NZFrom(result)); } return true; } @@ -202,9 +193,7 @@ bool TranslatorVisitor::thumb16_LSL_reg(Reg m, Reg d_n) { ir.SetRegister(d, result_carry.result); if (!ir.current_location.IT().IsInITBlock()) { - ir.SetNFlag(ir.MostSignificantBit(result_carry.result)); - ir.SetZFlag(ir.IsZero(result_carry.result)); - ir.SetCFlag(result_carry.carry); + ir.SetCpsrNZC(ir.NZFrom(result_carry.result), result_carry.carry); } return true; } @@ -219,9 +208,7 @@ bool TranslatorVisitor::thumb16_LSR_reg(Reg m, Reg d_n) { ir.SetRegister(d, result.result); if (!ir.current_location.IT().IsInITBlock()) { - ir.SetNFlag(ir.MostSignificantBit(result.result)); - ir.SetZFlag(ir.IsZero(result.result)); - ir.SetCFlag(result.carry); + ir.SetCpsrNZC(ir.NZFrom(result.result), result.carry); } return true; } @@ -236,9 +223,7 @@ bool TranslatorVisitor::thumb16_ASR_reg(Reg m, Reg d_n) { ir.SetRegister(d, result.result); if (!ir.current_location.IT().IsInITBlock()) { - ir.SetNFlag(ir.MostSignificantBit(result.result)); - ir.SetZFlag(ir.IsZero(result.result)); - ir.SetCFlag(result.carry); + ir.SetCpsrNZC(ir.NZFrom(result.result), result.carry); } return true; } @@ -283,9 +268,7 @@ bool TranslatorVisitor::thumb16_ROR_reg(Reg m, Reg d_n) { ir.SetRegister(d, result.result); if (!ir.current_location.IT().IsInITBlock()) { - ir.SetNFlag(ir.MostSignificantBit(result.result)); - ir.SetZFlag(ir.IsZero(result.result)); - ir.SetCFlag(result.carry); + ir.SetCpsrNZC(ir.NZFrom(result.result), result.carry); } return true; } @@ -293,8 +276,7 @@ bool TranslatorVisitor::thumb16_ROR_reg(Reg m, Reg d_n) { // TST , bool TranslatorVisitor::thumb16_TST_reg(Reg m, Reg n) { const auto result = ir.And(ir.GetRegister(n), ir.GetRegister(m)); - ir.SetNFlag(ir.MostSignificantBit(result)); - ir.SetZFlag(ir.IsZero(result)); + ir.SetCpsrNZ(ir.NZFrom(result)); return true; } @@ -332,8 +314,7 @@ bool TranslatorVisitor::thumb16_ORR_reg(Reg m, Reg d_n) { ir.SetRegister(d, result); if (!ir.current_location.IT().IsInITBlock()) { - ir.SetNFlag(ir.MostSignificantBit(result)); - ir.SetZFlag(ir.IsZero(result)); + ir.SetCpsrNZ(ir.NZFrom(result)); } return true; } @@ -347,8 +328,7 @@ bool TranslatorVisitor::thumb16_MUL_reg(Reg n, Reg d_m) { ir.SetRegister(d, result); if (!ir.current_location.IT().IsInITBlock()) { - ir.SetNFlag(ir.MostSignificantBit(result)); - ir.SetZFlag(ir.IsZero(result)); + ir.SetCpsrNZ(ir.NZFrom(result)); } return true; } @@ -362,8 +342,7 @@ bool TranslatorVisitor::thumb16_BIC_reg(Reg m, Reg d_n) { ir.SetRegister(d, result); if (!ir.current_location.IT().IsInITBlock()) { - ir.SetNFlag(ir.MostSignificantBit(result)); - ir.SetZFlag(ir.IsZero(result)); + ir.SetCpsrNZ(ir.NZFrom(result)); } return true; } @@ -375,8 +354,7 @@ bool TranslatorVisitor::thumb16_MVN_reg(Reg m, Reg d) { ir.SetRegister(d, result); if (!ir.current_location.IT().IsInITBlock()) { - ir.SetNFlag(ir.MostSignificantBit(result)); - ir.SetZFlag(ir.IsZero(result)); + ir.SetCpsrNZ(ir.NZFrom(result)); } return true; } diff --git a/src/dynarmic/frontend/A32/translate/impl/thumb32_data_processing_modified_immediate.cpp b/src/dynarmic/frontend/A32/translate/impl/thumb32_data_processing_modified_immediate.cpp index f2cb202b..0c0114f8 100644 --- a/src/dynarmic/frontend/A32/translate/impl/thumb32_data_processing_modified_immediate.cpp +++ b/src/dynarmic/frontend/A32/translate/impl/thumb32_data_processing_modified_immediate.cpp @@ -15,9 +15,7 @@ bool TranslatorVisitor::thumb32_TST_imm(Imm<1> i, Reg n, Imm<3> imm3, Imm<8> imm const auto imm_carry = ThumbExpandImm_C(i, imm3, imm8, ir.GetCFlag()); const auto result = ir.And(ir.GetRegister(n), ir.Imm32(imm_carry.imm32)); - ir.SetNFlag(ir.MostSignificantBit(result)); - ir.SetZFlag(ir.IsZero(result)); - ir.SetCFlag(imm_carry.carry); + ir.SetCpsrNZC(ir.NZFrom(result), imm_carry.carry); return true; } @@ -32,9 +30,7 @@ bool TranslatorVisitor::thumb32_AND_imm(Imm<1> i, bool S, Reg n, Imm<3> imm3, Re ir.SetRegister(d, result); if (S) { - ir.SetNFlag(ir.MostSignificantBit(result)); - ir.SetZFlag(ir.IsZero(result)); - ir.SetCFlag(imm_carry.carry); + ir.SetCpsrNZC(ir.NZFrom(result), imm_carry.carry); } return true; } @@ -49,9 +45,7 @@ bool TranslatorVisitor::thumb32_BIC_imm(Imm<1> i, bool S, Reg n, Imm<3> imm3, Re ir.SetRegister(d, result); if (S) { - ir.SetNFlag(ir.MostSignificantBit(result)); - ir.SetZFlag(ir.IsZero(result)); - ir.SetCFlag(imm_carry.carry); + ir.SetCpsrNZC(ir.NZFrom(result), imm_carry.carry); } return true; } @@ -66,9 +60,7 @@ bool TranslatorVisitor::thumb32_MOV_imm(Imm<1> i, bool S, Imm<3> imm3, Reg d, Im ir.SetRegister(d, result); if (S) { - ir.SetNFlag(ir.MostSignificantBit(result)); - ir.SetZFlag(ir.IsZero(result)); - ir.SetCFlag(imm_carry.carry); + ir.SetCpsrNZC(ir.NZFrom(result), imm_carry.carry); } return true; } @@ -84,9 +76,7 @@ bool TranslatorVisitor::thumb32_ORR_imm(Imm<1> i, bool S, Reg n, Imm<3> imm3, Re ir.SetRegister(d, result); if (S) { - ir.SetNFlag(ir.MostSignificantBit(result)); - ir.SetZFlag(ir.IsZero(result)); - ir.SetCFlag(imm_carry.carry); + ir.SetCpsrNZC(ir.NZFrom(result), imm_carry.carry); } return true; } @@ -101,9 +91,7 @@ bool TranslatorVisitor::thumb32_MVN_imm(Imm<1> i, bool S, Imm<3> imm3, Reg d, Im ir.SetRegister(d, result); if (S) { - ir.SetNFlag(ir.MostSignificantBit(result)); - ir.SetZFlag(ir.IsZero(result)); - ir.SetCFlag(imm_carry.carry); + ir.SetCpsrNZC(ir.NZFrom(result), imm_carry.carry); } return true; } @@ -119,9 +107,7 @@ bool TranslatorVisitor::thumb32_ORN_imm(Imm<1> i, bool S, Reg n, Imm<3> imm3, Re ir.SetRegister(d, result); if (S) { - ir.SetNFlag(ir.MostSignificantBit(result)); - ir.SetZFlag(ir.IsZero(result)); - ir.SetCFlag(imm_carry.carry); + ir.SetCpsrNZC(ir.NZFrom(result), imm_carry.carry); } return true; } @@ -134,9 +120,7 @@ bool TranslatorVisitor::thumb32_TEQ_imm(Imm<1> i, Reg n, Imm<3> imm3, Imm<8> imm const auto imm_carry = ThumbExpandImm_C(i, imm3, imm8, ir.GetCFlag()); const auto result = ir.Eor(ir.GetRegister(n), ir.Imm32(imm_carry.imm32)); - ir.SetNFlag(ir.MostSignificantBit(result)); - ir.SetZFlag(ir.IsZero(result)); - ir.SetCFlag(imm_carry.carry); + ir.SetCpsrNZC(ir.NZFrom(result), imm_carry.carry); return true; } @@ -151,9 +135,7 @@ bool TranslatorVisitor::thumb32_EOR_imm(Imm<1> i, bool S, Reg n, Imm<3> imm3, Re ir.SetRegister(d, result); if (S) { - ir.SetNFlag(ir.MostSignificantBit(result)); - ir.SetZFlag(ir.IsZero(result)); - ir.SetCFlag(imm_carry.carry); + ir.SetCpsrNZC(ir.NZFrom(result), imm_carry.carry); } return true; } diff --git a/src/dynarmic/frontend/A32/translate/impl/thumb32_data_processing_register.cpp b/src/dynarmic/frontend/A32/translate/impl/thumb32_data_processing_register.cpp index 04f5803c..1dda532d 100644 --- a/src/dynarmic/frontend/A32/translate/impl/thumb32_data_processing_register.cpp +++ b/src/dynarmic/frontend/A32/translate/impl/thumb32_data_processing_register.cpp @@ -24,9 +24,7 @@ bool ShiftInstruction(TranslatorVisitor& v, Reg m, Reg d, Reg s, bool S, ShiftFu const auto result_carry = (v.ir.*shift_fn)(v.ir.GetRegister(m), shift_s, apsr_c); if (S) { - v.ir.SetNFlag(v.ir.MostSignificantBit(result_carry.result)); - v.ir.SetZFlag(v.ir.IsZero(result_carry.result)); - v.ir.SetCFlag(result_carry.carry); + v.ir.SetCpsrNZC(v.ir.NZFrom(result_carry.result), result_carry.carry); } v.ir.SetRegister(d, result_carry.result); diff --git a/src/dynarmic/frontend/A32/translate/impl/thumb32_data_processing_shifted_register.cpp b/src/dynarmic/frontend/A32/translate/impl/thumb32_data_processing_shifted_register.cpp index ee62bb52..30583500 100644 --- a/src/dynarmic/frontend/A32/translate/impl/thumb32_data_processing_shifted_register.cpp +++ b/src/dynarmic/frontend/A32/translate/impl/thumb32_data_processing_shifted_register.cpp @@ -15,9 +15,7 @@ bool TranslatorVisitor::thumb32_TST_reg(Reg n, Imm<3> imm3, Imm<2> imm2, ShiftTy const auto shifted = EmitImmShift(ir.GetRegister(m), type, imm3, imm2, ir.GetCFlag()); const auto result = ir.And(ir.GetRegister(n), shifted.result); - ir.SetNFlag(ir.MostSignificantBit(result)); - ir.SetZFlag(ir.IsZero(result)); - ir.SetCFlag(shifted.carry); + ir.SetCpsrNZC(ir.NZFrom(result), shifted.carry); return true; } @@ -32,9 +30,7 @@ bool TranslatorVisitor::thumb32_AND_reg(bool S, Reg n, Imm<3> imm3, Reg d, Imm<2 const auto result = ir.And(ir.GetRegister(n), shifted.result); ir.SetRegister(d, result); if (S) { - ir.SetNFlag(ir.MostSignificantBit(result)); - ir.SetZFlag(ir.IsZero(result)); - ir.SetCFlag(shifted.carry); + ir.SetCpsrNZC(ir.NZFrom(result), shifted.carry); } return true; } @@ -48,9 +44,7 @@ bool TranslatorVisitor::thumb32_BIC_reg(bool S, Reg n, Imm<3> imm3, Reg d, Imm<2 const auto result = ir.AndNot(ir.GetRegister(n), shifted.result); ir.SetRegister(d, result); if (S) { - ir.SetNFlag(ir.MostSignificantBit(result)); - ir.SetZFlag(ir.IsZero(result)); - ir.SetCFlag(shifted.carry); + ir.SetCpsrNZC(ir.NZFrom(result), shifted.carry); } return true; } @@ -64,9 +58,7 @@ bool TranslatorVisitor::thumb32_MOV_reg(bool S, Imm<3> imm3, Reg d, Imm<2> imm2, const auto result = shifted.result; ir.SetRegister(d, result); if (S) { - ir.SetNFlag(ir.MostSignificantBit(result)); - ir.SetZFlag(ir.IsZero(result)); - ir.SetCFlag(shifted.carry); + ir.SetCpsrNZC(ir.NZFrom(result), shifted.carry); } return true; } @@ -82,9 +74,7 @@ bool TranslatorVisitor::thumb32_ORR_reg(bool S, Reg n, Imm<3> imm3, Reg d, Imm<2 const auto result = ir.Or(ir.GetRegister(n), shifted.result); ir.SetRegister(d, result); if (S) { - ir.SetNFlag(ir.MostSignificantBit(result)); - ir.SetZFlag(ir.IsZero(result)); - ir.SetCFlag(shifted.carry); + ir.SetCpsrNZC(ir.NZFrom(result), shifted.carry); } return true; } @@ -98,9 +88,7 @@ bool TranslatorVisitor::thumb32_MVN_reg(bool S, Imm<3> imm3, Reg d, Imm<2> imm2, const auto result = ir.Not(shifted.result); ir.SetRegister(d, result); if (S) { - ir.SetNFlag(ir.MostSignificantBit(result)); - ir.SetZFlag(ir.IsZero(result)); - ir.SetCFlag(shifted.carry); + ir.SetCpsrNZC(ir.NZFrom(result), shifted.carry); } return true; } @@ -116,9 +104,7 @@ bool TranslatorVisitor::thumb32_ORN_reg(bool S, Reg n, Imm<3> imm3, Reg d, Imm<2 const auto result = ir.Or(ir.GetRegister(n), ir.Not(shifted.result)); ir.SetRegister(d, result); if (S) { - ir.SetNFlag(ir.MostSignificantBit(result)); - ir.SetZFlag(ir.IsZero(result)); - ir.SetCFlag(shifted.carry); + ir.SetCpsrNZC(ir.NZFrom(result), shifted.carry); } return true; } @@ -131,9 +117,7 @@ bool TranslatorVisitor::thumb32_TEQ_reg(Reg n, Imm<3> imm3, Imm<2> imm2, ShiftTy const auto shifted = EmitImmShift(ir.GetRegister(m), type, imm3, imm2, ir.GetCFlag()); const auto result = ir.Eor(ir.GetRegister(n), shifted.result); - ir.SetNFlag(ir.MostSignificantBit(result)); - ir.SetZFlag(ir.IsZero(result)); - ir.SetCFlag(shifted.carry); + ir.SetCpsrNZC(ir.NZFrom(result), shifted.carry); return true; } @@ -148,9 +132,7 @@ bool TranslatorVisitor::thumb32_EOR_reg(bool S, Reg n, Imm<3> imm3, Reg d, Imm<2 const auto result = ir.Eor(ir.GetRegister(n), shifted.result); ir.SetRegister(d, result); if (S) { - ir.SetNFlag(ir.MostSignificantBit(result)); - ir.SetZFlag(ir.IsZero(result)); - ir.SetCFlag(shifted.carry); + ir.SetCpsrNZC(ir.NZFrom(result), shifted.carry); } return true; } diff --git a/src/dynarmic/ir/microinstruction.cpp b/src/dynarmic/ir/microinstruction.cpp index 88ce4915..3fddb387 100644 --- a/src/dynarmic/ir/microinstruction.cpp +++ b/src/dynarmic/ir/microinstruction.cpp @@ -176,10 +176,8 @@ bool Inst::WritesToCPSR() const { case Opcode::A32SetCpsrNZCVRaw: case Opcode::A32SetCpsrNZCV: case Opcode::A32SetCpsrNZCVQ: - case Opcode::A32SetNFlag: - case Opcode::A32SetZFlag: - case Opcode::A32SetCFlag: - case Opcode::A32SetVFlag: + case Opcode::A32SetCpsrNZ: + case Opcode::A32SetCpsrNZC: case Opcode::A32OrQFlag: case Opcode::A32SetGEFlags: case Opcode::A32SetGEFlagsCompressed: @@ -546,6 +544,7 @@ bool Inst::IsAPseudoOperation() const { case Opcode::GetOverflowFromOp: case Opcode::GetGEFromOp: case Opcode::GetNZCVFromOp: + case Opcode::GetNZFromOp: case Opcode::GetUpperFromOp: case Opcode::GetLowerFromOp: case Opcode::MostSignificantBit: @@ -669,7 +668,7 @@ void Inst::Use(const Value& value) { Inst* insert_point = value.GetInst(); while (insert_point->next_pseudoop) { insert_point = insert_point->next_pseudoop; - DEBUG_ASSERT(insert_point->GetArg(0).GetInst() == this); + DEBUG_ASSERT(insert_point->GetArg(0).GetInst() == value.GetInst()); } insert_point->next_pseudoop = this; } @@ -682,7 +681,7 @@ void Inst::UndoUse(const Value& value) { Inst* insert_point = value.GetInst(); while (insert_point->next_pseudoop != this) { insert_point = insert_point->next_pseudoop; - DEBUG_ASSERT(insert_point->GetArg(0).GetInst() == this); + DEBUG_ASSERT(insert_point->GetArg(0).GetInst() == value.GetInst()); } insert_point->next_pseudoop = next_pseudoop; next_pseudoop = nullptr; diff --git a/src/dynarmic/ir/opcodes.inc b/src/dynarmic/ir/opcodes.inc index 791c29a5..335d4477 100644 --- a/src/dynarmic/ir/opcodes.inc +++ b/src/dynarmic/ir/opcodes.inc @@ -22,11 +22,9 @@ A32OPC(SetCpsr, Void, U32 A32OPC(SetCpsrNZCV, Void, NZCV ) A32OPC(SetCpsrNZCVRaw, Void, U32 ) A32OPC(SetCpsrNZCVQ, Void, U32 ) -A32OPC(SetNFlag, Void, U1 ) -A32OPC(SetZFlag, Void, U1 ) +A32OPC(SetCpsrNZ, Void, NZCV ) +A32OPC(SetCpsrNZC, Void, NZCV, U1 ) A32OPC(GetCFlag, U1, ) -A32OPC(SetCFlag, Void, U1 ) -A32OPC(SetVFlag, Void, U1 ) A32OPC(OrQFlag, Void, U1 ) A32OPC(GetGEFlags, U32, ) A32OPC(SetGEFlags, Void, U32 ) @@ -90,6 +88,7 @@ OPCODE(GetCarryFromOp, U1, Opaq OPCODE(GetOverflowFromOp, U1, Opaque ) OPCODE(GetGEFromOp, U32, Opaque ) OPCODE(GetNZCVFromOp, NZCV, Opaque ) +OPCODE(GetNZFromOp, NZCV, Opaque ) OPCODE(GetUpperFromOp, U128, Opaque ) OPCODE(GetLowerFromOp, U128, Opaque ) diff --git a/src/dynarmic/ir/opt/a32_constant_memory_reads_pass.cpp b/src/dynarmic/ir/opt/a32_constant_memory_reads_pass.cpp index 828a7687..9699f183 100644 --- a/src/dynarmic/ir/opt/a32_constant_memory_reads_pass.cpp +++ b/src/dynarmic/ir/opt/a32_constant_memory_reads_pass.cpp @@ -13,13 +13,6 @@ namespace Dynarmic::Optimization { void A32ConstantMemoryReads(IR::Block& block, A32::UserCallbacks* cb) { for (auto& inst : block) { switch (inst.GetOpcode()) { - case IR::Opcode::A32SetCFlag: { - const IR::Value arg = inst.GetArg(0); - if (!arg.IsImmediate() && arg.GetInst()->GetOpcode() == IR::Opcode::A32GetCFlag) { - inst.Invalidate(); - } - break; - } case IR::Opcode::A32ReadMemory8: { if (!inst.AreAllArgsImmediates()) { break; diff --git a/src/dynarmic/ir/opt/a32_get_set_elimination_pass.cpp b/src/dynarmic/ir/opt/a32_get_set_elimination_pass.cpp index 2689d194..26823517 100644 --- a/src/dynarmic/ir/opt/a32_get_set_elimination_pass.cpp +++ b/src/dynarmic/ir/opt/a32_get_set_elimination_pass.cpp @@ -29,24 +29,34 @@ void A32GetSetElimination(IR::Block& block) { std::array ext_reg_vector_double_info; std::array ext_reg_vector_quad_info; struct CpsrInfo { - RegisterInfo n; - RegisterInfo z; + RegisterInfo nz; RegisterInfo c; - RegisterInfo v; + RegisterInfo nzc; + RegisterInfo nzcv; RegisterInfo ge; } cpsr_info; - const auto do_set = [&block](RegisterInfo& info, IR::Value value, Iterator set_inst) { + const auto do_delete_last_set = [&block](RegisterInfo& info) { if (info.set_instruction_present) { + info.set_instruction_present = false; info.last_set_instruction->Invalidate(); block.Instructions().erase(info.last_set_instruction); } + info = {}; + }; + const auto do_set = [&do_delete_last_set](RegisterInfo& info, IR::Value value, Iterator set_inst) { + do_delete_last_set(info); info.register_value = value; info.set_instruction_present = true; info.last_set_instruction = set_inst; }; + const auto do_set_without_inst = [&do_delete_last_set](RegisterInfo& info, IR::Value value) { + do_delete_last_set(info); + info.register_value = value; + }; + const auto do_get = [](RegisterInfo& info, Iterator get_inst) { if (info.register_value.IsEmpty()) { info.register_value = IR::Value(&*get_inst); @@ -167,24 +177,40 @@ void A32GetSetElimination(IR::Block& block) { } break; } - case IR::Opcode::A32SetNFlag: { - do_set(cpsr_info.n, inst->GetArg(0), inst); - break; - } - case IR::Opcode::A32SetZFlag: { - do_set(cpsr_info.z, inst->GetArg(0), inst); - break; - } - case IR::Opcode::A32SetCFlag: { - do_set(cpsr_info.c, inst->GetArg(0), inst); - break; - } case IR::Opcode::A32GetCFlag: { do_get(cpsr_info.c, inst); + // ensure source is not deleted + cpsr_info.nzc = {}; + cpsr_info.nzcv = {}; break; } - case IR::Opcode::A32SetVFlag: { - do_set(cpsr_info.v, inst->GetArg(0), inst); + case IR::Opcode::A32SetCpsrNZCV: + case IR::Opcode::A32SetCpsrNZCVRaw: { + do_delete_last_set(cpsr_info.nz); + do_delete_last_set(cpsr_info.c); + do_delete_last_set(cpsr_info.nzc); + do_set(cpsr_info.nzcv, inst->GetArg(0), inst); + break; + } + case IR::Opcode::A32SetCpsrNZCVQ: { + do_delete_last_set(cpsr_info.nz); + do_delete_last_set(cpsr_info.c); + do_delete_last_set(cpsr_info.nzc); + do_delete_last_set(cpsr_info.nzcv); + break; + } + case IR::Opcode::A32SetCpsrNZ: { + // cpsr_info.c remains valid + cpsr_info.nzc = {}; // TODO: Consider reduction of previous to a SetCFlag operation + cpsr_info.nzcv = {}; + do_set(cpsr_info.nz, inst->GetArg(0), inst); + break; + } + case IR::Opcode::A32SetCpsrNZC: { + cpsr_info.nzcv = {}; + do_set(cpsr_info.nzc, {}, inst); + do_set_without_inst(cpsr_info.nz, inst->GetArg(0)); + do_set_without_inst(cpsr_info.c, inst->GetArg(1)); break; } case IR::Opcode::A32SetGEFlags: { diff --git a/tests/A32/test_thumb_instructions.cpp b/tests/A32/test_thumb_instructions.cpp index c403f8bb..6ed59e25 100644 --- a/tests/A32/test_thumb_instructions.cpp +++ b/tests/A32/test_thumb_instructions.cpp @@ -156,3 +156,99 @@ TEST_CASE("thumb: bl -#42", "[thumb]") { REQUIRE(jit.Regs()[15] == 0xFFFFFFD6); REQUIRE(jit.Cpsr() == 0x00000030); // Thumb, User-mode } + +TEST_CASE("thumb: Opt Failure: Get/Set Elimination for Flags", "[thumb]") { + // This was a randomized test-case that was failing. + // + // Incorrect IR: + // Block: location={0000000100000000} + // cycles=6, entry_cond=al + // [0000556569455160] %0 = GetRegister r1 (uses: 1) + // [00005565694551c8] %1 = GetRegister r6 (uses: 1) + // [0000556569455230] %2 = Mul32 %1, %0 (uses: 1) + // [0000556569455298] SetRegister r6, %2 (uses: 0) + // [0000556569455300] Void (uses: 0) + // [00005565694553d0] Void (uses: 0) + // [0000556569455438] Void (uses: 0) + // [00005565694554a0] Void (uses: 0) + // [0000556569455508] Void (uses: 0) + // [00005565694555d8] %9 = GetCFlag (uses: 1) + // [0000556569455640] %10 = GetRegister r3 (uses: 2) + // [00005565694556a8] %11 = Identity %10 (uses: 1) + // [0000556569455710] %12 = Add32 %11, %10, %9 (uses: 2) + // [0000556569455778] SetRegister r3, %12 (uses: 0) + // [00005565694557e0] %14 = GetNZCVFromOp %12 (uses: 1) + // [0000556569455848] SetCpsrNZCV %14 (uses: 0) + // [00005565694558b0] %16 = GetRegister sp (uses: 1) + // [0000556569455918] %17 = Add32 %16, #0x2c4, #0 (uses: 1) + // [0000556569455980] %18 = GetRegister r4 (uses: 1) + // [00005565694559e8] WriteMemory32 #0x100000006, %17, %18, (uses: 0) + // [0000556569455a50] %20 = GetRegister r2 (uses: 1) + // [0000556569455ab8] %21 = GetRegister r5 (uses: 1) + // [0000556569455b20] %22 = Add32 %21, %20, #0 (uses: 1) + // [0000556569455b88] SetRegister r5, %22 (uses: 0) + // terminal = LinkBlock{{000000010000000a}} + + ThumbTestEnv test_env; + Dynarmic::A32::Jit jit{GetUserConfig(&test_env)}; + test_env.code_mem = { + 0x434e, // muls r6, r1, r6 + 0x4557, // cmp r7, r10 + 0x415b, // adcs r3, r3 + 0x94b1, // str r4, [sp, #708] + 0x4415, // add r5, r2 + 0xe7fe // b +#0 + }; + + jit.Regs() = {0x2154abb5, 0xdbaa6333, 0xf8a7bc0e, 0x989f6096, 0x19cd7783, 0xe1cf5b7f, 0x9bb1aa6c, 0x6b700f5c, + 0xc04f6cb2, 0xc8df07f0, 0x217d83de, 0xe77fdffa, 0x98bcceaf, 0xbfcab4f7, 0xdb9d5405, 0x00000000}; + jit.SetCpsr(0x000001f0); // Thumb, User-mode + + test_env.ticks_left = 7; + jit.Run(); + + REQUIRE(jit.Regs()[0] == 0x2154abb5); + REQUIRE(jit.Regs()[1] == 0xdbaa6333); + REQUIRE(jit.Regs()[2] == 0xf8a7bc0e); + REQUIRE(jit.Regs()[3] == 0x313ec12d); + REQUIRE(jit.Regs()[4] == 0x19cd7783); + REQUIRE(jit.Regs()[5] == 0xda77178d); + REQUIRE(jit.Regs()[6] == 0x4904b784); + REQUIRE(jit.Regs()[7] == 0x6b700f5c); + REQUIRE(jit.Regs()[8] == 0xc04f6cb2); + REQUIRE(jit.Regs()[9] == 0xc8df07f0); + REQUIRE(jit.Regs()[10] == 0x217d83de); + REQUIRE(jit.Regs()[11] == 0xe77fdffa); + REQUIRE(jit.Regs()[12] == 0x98bcceaf); + REQUIRE(jit.Regs()[13] == 0xbfcab4f7); + REQUIRE(jit.Regs()[14] == 0xdb9d5405); + REQUIRE(jit.Regs()[15] == 0x0000000a); + REQUIRE(jit.Cpsr() == 0x300001f0); +} + +TEST_CASE("thumb: Opt Failure: Get/Set Elimination for Flags 2", "[thumb]") { + // This was a randomized test-case that was failing. + + ThumbTestEnv test_env; + Dynarmic::A32::Jit jit{GetUserConfig(&test_env)}; + test_env.code_mem = { + 0x442a, // add r2, r5 + 0x065d, // lsls r5, r3, #25 + 0xbc64, // pop {r2, r5, r6} + 0x2666, // movs r6, #102 + 0x7471, // strb r1, [r6, #17] + 0xe7fe // b +#0 + }; + + jit.Regs() = {0x954d53b0, 0x4caaad40, 0xa42325b8, 0x0da0cdb6, 0x0f43507e, 0x31d68ae1, 0x9c471808, 0x892a6888, + 0x3b9ffb23, 0x0a92ef93, 0x38dee619, 0xc0e95e81, 0x6a448690, 0xc2d4d6ad, 0xe93600b9, 0x00000000}; + jit.SetCpsr(0x000001f0); // Thumb, User-mode + + test_env.ticks_left = 7; + jit.Run(); + + const std::array expected = {0x954d53b0, 0x4caaad40, 0xb0afaead, 0x0da0cdb6, 0x0f43507e, 0xb4b3b2b1, 0x00000066, 0x892a6888, + 0x3b9ffb23, 0x0a92ef93, 0x38dee619, 0xc0e95e81, 0x6a448690, 0xc2d4d6b9, 0xe93600b9, 0x0000000a}; + REQUIRE(jit.Regs() == expected); + REQUIRE(jit.Cpsr() == 0x200001f0); +}