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:
parent
2e1ab36240
commit
cf08130f2c
15 changed files with 284 additions and 271 deletions
|
@ -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()) {
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 )
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue