A32: Condense flag handling

Remove individual flag handlers, and handle them in chuks where able, to produce more optimal code.
This commit is contained in:
Merry 2022-07-17 15:34:11 +01:00
parent 2e1ab36240
commit cf08130f2c
15 changed files with 284 additions and 271 deletions

View file

@ -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<int>(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()) {

View file

@ -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);

View file

@ -166,22 +166,6 @@ IR::U1 IREmitter::GetCFlag() {
return Inst<IR::U1>(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<IR::NZCV>(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);
}

View file

@ -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();

View file

@ -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;
}

View file

@ -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;

View file

@ -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 <Rn>, <Rm>
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;
}

View file

@ -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;
}

View file

@ -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);

View file

@ -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;
}

View file

@ -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;

View file

@ -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 )

View file

@ -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;

View file

@ -29,24 +29,34 @@ void A32GetSetElimination(IR::Block& block) {
std::array<RegisterInfo, 32> ext_reg_vector_double_info;
std::array<RegisterInfo, 16> 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: {

View file

@ -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, <unknown immediate type> (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<u32, 16> 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);
}