From ccf27f9c8c67e13817f7fd2ce2010cf72375991a Mon Sep 17 00:00:00 2001
From: SachinVin <sachinvinayak2000@gmail.com>
Date: Mon, 24 May 2021 19:13:55 +0530
Subject: [PATCH] ir_emitter:  Remove 32-bit-only `AddWithCarry`

---
 src/dynarmic/backend/x64/a32_emit_x64.cpp     |  6 ++
 src/dynarmic/frontend/A32/ir_emitter.cpp      | 10 ++-
 src/dynarmic/frontend/A32/ir_emitter.h        |  4 +-
 .../A32/translate/impl/coprocessor.cpp        |  2 +-
 .../A32/translate/impl/data_processing.cpp    | 65 ++++++-------------
 .../frontend/A32/translate/impl/multiply.cpp  | 40 ++++++------
 .../frontend/A32/translate/impl/parallel.cpp  |  2 +-
 .../frontend/A32/translate/impl/thumb16.cpp   | 41 ++++--------
 .../translate/impl/thumb32_coprocessor.cpp    |  2 +-
 ...b32_data_processing_modified_immediate.cpp | 19 ++----
 ...data_processing_plain_binary_immediate.cpp |  2 +-
 ...umb32_data_processing_shifted_register.cpp | 19 ++----
 .../A32/translate/impl/thumb32_multiply.cpp   | 42 ++++++------
 .../frontend/A32/translate/impl/vfp.cpp       |  2 +-
 src/dynarmic/ir/ir_emitter.cpp                |  7 --
 src/dynarmic/ir/ir_emitter.h                  |  1 -
 src/dynarmic/ir/microinstruction.cpp          |  1 +
 src/dynarmic/ir/opcodes.inc                   |  3 +-
 18 files changed, 109 insertions(+), 159 deletions(-)

diff --git a/src/dynarmic/backend/x64/a32_emit_x64.cpp b/src/dynarmic/backend/x64/a32_emit_x64.cpp
index e2c56b21..37f97207 100644
--- a/src/dynarmic/backend/x64/a32_emit_x64.cpp
+++ b/src/dynarmic/backend/x64/a32_emit_x64.cpp
@@ -541,6 +541,12 @@ void A32EmitX64::EmitA32SetCpsr(A32EmitContext& ctx, IR::Inst* inst) {
 }
 
 void A32EmitX64::EmitA32SetCpsrNZCV(A32EmitContext& ctx, IR::Inst* inst) {
+    auto args = ctx.reg_alloc.GetArgumentInfo(inst);
+    const Xbyak::Reg32 to_store = ctx.reg_alloc.UseScratchGpr(args[0]).cvt32();
+    code.mov(dword[r15 + offsetof(A32JitState, cpsr_nzcv)], to_store);
+}
+
+void A32EmitX64::EmitA32SetCpsrNZCVRaw(A32EmitContext& ctx, IR::Inst* inst) {
     auto args = ctx.reg_alloc.GetArgumentInfo(inst);
     if (args[0].IsImmediate()) {
         const u32 imm = args[0].GetImmediateU32();
diff --git a/src/dynarmic/frontend/A32/ir_emitter.cpp b/src/dynarmic/frontend/A32/ir_emitter.cpp
index 9839beca..c948a78f 100644
--- a/src/dynarmic/frontend/A32/ir_emitter.cpp
+++ b/src/dynarmic/frontend/A32/ir_emitter.cpp
@@ -141,10 +141,14 @@ void IREmitter::SetCpsr(const IR::U32& value) {
     Inst(Opcode::A32SetCpsr, value);
 }
 
-void IREmitter::SetCpsrNZCV(const IR::U32& value) {
+void IREmitter::SetCpsrNZCV(const IR::NZCV& value) {
     Inst(Opcode::A32SetCpsrNZCV, value);
 }
 
+void IREmitter::SetCpsrNZCVRaw(const IR::U32& value) {
+    Inst(Opcode::A32SetCpsrNZCVRaw, value);
+}
+
 void IREmitter::SetCpsrNZCVQ(const IR::U32& value) {
     Inst(Opcode::A32SetCpsrNZCVQ, value);
 }
@@ -153,6 +157,10 @@ void IREmitter::SetCheckBit(const IR::U1& value) {
     Inst(Opcode::A32SetCheckBit, value);
 }
 
+IR::U1 IREmitter::GetOverflowFrom(const IR::Value& value) {
+    return Inst<IR::U1>(Opcode::GetOverflowFromOp, value);
+}
+
 IR::U1 IREmitter::GetCFlag() {
     return Inst<IR::U1>(Opcode::A32GetCFlag);
 }
diff --git a/src/dynarmic/frontend/A32/ir_emitter.h b/src/dynarmic/frontend/A32/ir_emitter.h
index 80bcf6b9..9377a5c8 100644
--- a/src/dynarmic/frontend/A32/ir_emitter.h
+++ b/src/dynarmic/frontend/A32/ir_emitter.h
@@ -55,9 +55,11 @@ public:
 
     IR::U32 GetCpsr();
     void SetCpsr(const IR::U32& value);
-    void SetCpsrNZCV(const IR::U32& value);
+    void SetCpsrNZCV(const IR::NZCV& value);
+    void SetCpsrNZCVRaw(const IR::U32& value);
     void SetCpsrNZCVQ(const IR::U32& value);
     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);
diff --git a/src/dynarmic/frontend/A32/translate/impl/coprocessor.cpp b/src/dynarmic/frontend/A32/translate/impl/coprocessor.cpp
index 63a233f0..402efd4b 100644
--- a/src/dynarmic/frontend/A32/translate/impl/coprocessor.cpp
+++ b/src/dynarmic/frontend/A32/translate/impl/coprocessor.cpp
@@ -102,7 +102,7 @@ bool TranslatorVisitor::arm_MRC(Cond cond, size_t opc1, CoprocReg CRn, Reg t, si
             ir.SetRegister(t, word);
         } else {
             const auto new_cpsr_nzcv = ir.And(word, ir.Imm32(0xF0000000));
-            ir.SetCpsrNZCV(new_cpsr_nzcv);
+            ir.SetCpsrNZCVRaw(new_cpsr_nzcv);
         }
     }
     return true;
diff --git a/src/dynarmic/frontend/A32/translate/impl/data_processing.cpp b/src/dynarmic/frontend/A32/translate/impl/data_processing.cpp
index ef038d2b..c6fa5300 100644
--- a/src/dynarmic/frontend/A32/translate/impl/data_processing.cpp
+++ b/src/dynarmic/frontend/A32/translate/impl/data_processing.cpp
@@ -21,17 +21,14 @@ bool TranslatorVisitor::arm_ADC_imm(Cond cond, bool S, Reg n, Reg d, int rotate,
             return UnpredictableInstruction();
         }
 
-        ir.ALUWritePC(result.result);
+        ir.ALUWritePC(result);
         ir.SetTerm(IR::Term::ReturnToDispatch{});
         return false;
     }
 
-    ir.SetRegister(d, result.result);
+    ir.SetRegister(d, result);
     if (S) {
-        ir.SetNFlag(ir.MostSignificantBit(result.result));
-        ir.SetZFlag(ir.IsZero(result.result));
-        ir.SetCFlag(result.carry);
-        ir.SetVFlag(result.overflow);
+        ir.SetCpsrNZCV(ir.NZCVFrom(result));
     }
     return true;
 }
@@ -50,17 +47,14 @@ bool TranslatorVisitor::arm_ADC_reg(Cond cond, bool S, Reg n, Reg d, Imm<5> imm5
             return UnpredictableInstruction();
         }
 
-        ir.ALUWritePC(result.result);
+        ir.ALUWritePC(result);
         ir.SetTerm(IR::Term::ReturnToDispatch{});
         return false;
     }
 
-    ir.SetRegister(d, result.result);
+    ir.SetRegister(d, result);
     if (S) {
-        ir.SetNFlag(ir.MostSignificantBit(result.result));
-        ir.SetZFlag(ir.IsZero(result.result));
-        ir.SetCFlag(result.carry);
-        ir.SetVFlag(result.overflow);
+        ir.SetCpsrNZCV(ir.NZCVFrom(result));
     }
 
     return true;
@@ -81,12 +75,9 @@ bool TranslatorVisitor::arm_ADC_rsr(Cond cond, bool S, Reg n, Reg d, Reg s, Shif
     const auto shifted = EmitRegShift(ir.GetRegister(m), shift, shift_n, carry_in);
     const auto result = ir.AddWithCarry(ir.GetRegister(n), shifted.result, ir.GetCFlag());
 
-    ir.SetRegister(d, result.result);
+    ir.SetRegister(d, result);
     if (S) {
-        ir.SetNFlag(ir.MostSignificantBit(result.result));
-        ir.SetZFlag(ir.IsZero(result.result));
-        ir.SetCFlag(result.carry);
-        ir.SetVFlag(result.overflow);
+        ir.SetCpsrNZCV(ir.NZCVFrom(result));
     }
 
     return true;
@@ -106,17 +97,14 @@ bool TranslatorVisitor::arm_ADD_imm(Cond cond, bool S, Reg n, Reg d, int rotate,
             return UnpredictableInstruction();
         }
 
-        ir.ALUWritePC(result.result);
+        ir.ALUWritePC(result);
         ir.SetTerm(IR::Term::ReturnToDispatch{});
         return false;
     }
 
-    ir.SetRegister(d, result.result);
+    ir.SetRegister(d, result);
     if (S) {
-        ir.SetNFlag(ir.MostSignificantBit(result.result));
-        ir.SetZFlag(ir.IsZero(result.result));
-        ir.SetCFlag(result.carry);
-        ir.SetVFlag(result.overflow);
+        ir.SetCpsrNZCV(ir.NZCVFrom(result));
     }
 
     return true;
@@ -136,17 +124,14 @@ bool TranslatorVisitor::arm_ADD_reg(Cond cond, bool S, Reg n, Reg d, Imm<5> imm5
             return UnpredictableInstruction();
         }
 
-        ir.ALUWritePC(result.result);
+        ir.ALUWritePC(result);
         ir.SetTerm(IR::Term::ReturnToDispatch{});
         return false;
     }
 
-    ir.SetRegister(d, result.result);
+    ir.SetRegister(d, result);
     if (S) {
-        ir.SetNFlag(ir.MostSignificantBit(result.result));
-        ir.SetZFlag(ir.IsZero(result.result));
-        ir.SetCFlag(result.carry);
-        ir.SetVFlag(result.overflow);
+        ir.SetCpsrNZCV(ir.NZCVFrom(result));
     }
 
     return true;
@@ -167,12 +152,9 @@ bool TranslatorVisitor::arm_ADD_rsr(Cond cond, bool S, Reg n, Reg d, Reg s, Shif
     const auto shifted = EmitRegShift(ir.GetRegister(m), shift, shift_n, carry_in);
     const auto result = ir.AddWithCarry(ir.GetRegister(n), shifted.result, ir.Imm1(0));
 
-    ir.SetRegister(d, result.result);
+    ir.SetRegister(d, result);
     if (S) {
-        ir.SetNFlag(ir.MostSignificantBit(result.result));
-        ir.SetZFlag(ir.IsZero(result.result));
-        ir.SetCFlag(result.carry);
-        ir.SetVFlag(result.overflow);
+        ir.SetCpsrNZCV(ir.NZCVFrom(result));
     }
 
     return true;
@@ -354,10 +336,7 @@ bool TranslatorVisitor::arm_CMN_imm(Cond cond, Reg n, int rotate, Imm<8> imm8) {
     const u32 imm32 = ArmExpandImm(rotate, imm8);
     const auto result = ir.AddWithCarry(ir.GetRegister(n), ir.Imm32(imm32), ir.Imm1(0));
 
-    ir.SetNFlag(ir.MostSignificantBit(result.result));
-    ir.SetZFlag(ir.IsZero(result.result));
-    ir.SetCFlag(result.carry);
-    ir.SetVFlag(result.overflow);
+    ir.SetCpsrNZCV(ir.NZCVFrom(result));
     return true;
 }
 
@@ -370,10 +349,7 @@ bool TranslatorVisitor::arm_CMN_reg(Cond cond, Reg n, Imm<5> imm5, ShiftType shi
     const auto shifted = EmitImmShift(ir.GetRegister(m), shift, imm5, ir.GetCFlag());
     const auto result = ir.AddWithCarry(ir.GetRegister(n), shifted.result, ir.Imm1(0));
 
-    ir.SetNFlag(ir.MostSignificantBit(result.result));
-    ir.SetZFlag(ir.IsZero(result.result));
-    ir.SetCFlag(result.carry);
-    ir.SetVFlag(result.overflow);
+    ir.SetCpsrNZCV(ir.NZCVFrom(result));
     return true;
 }
 
@@ -392,10 +368,7 @@ bool TranslatorVisitor::arm_CMN_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.AddWithCarry(ir.GetRegister(n), shifted.result, ir.Imm1(0));
 
-    ir.SetNFlag(ir.MostSignificantBit(result.result));
-    ir.SetZFlag(ir.IsZero(result.result));
-    ir.SetCFlag(result.carry);
-    ir.SetVFlag(result.overflow);
+    ir.SetCpsrNZCV(ir.NZCVFrom(result));
     return true;
 }
 
diff --git a/src/dynarmic/frontend/A32/translate/impl/multiply.cpp b/src/dynarmic/frontend/A32/translate/impl/multiply.cpp
index 3af0600d..0c497a87 100644
--- a/src/dynarmic/frontend/A32/translate/impl/multiply.cpp
+++ b/src/dynarmic/frontend/A32/translate/impl/multiply.cpp
@@ -260,10 +260,10 @@ bool TranslatorVisitor::arm_SMLAxy(Cond cond, Reg d, Reg a, Reg m, bool M, bool
     const IR::U32 m16 = M ? ir.ArithmeticShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result
                           : ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32));
     const IR::U32 product = ir.Mul(n16, m16);
-    const auto result_overflow = ir.AddWithCarry(product, ir.GetRegister(a), ir.Imm1(0));
+    const auto result = ir.AddWithCarry(product, ir.GetRegister(a), ir.Imm1(0));
 
-    ir.SetRegister(d, result_overflow.result);
-    ir.OrQFlag(result_overflow.overflow);
+    ir.SetRegister(d, result);
+    ir.OrQFlag(ir.GetOverflowFrom(result));
     return true;
 }
 
@@ -306,10 +306,10 @@ bool TranslatorVisitor::arm_SMLAWy(Cond cond, Reg d, Reg a, Reg m, bool M, Reg n
     }
     const IR::U64 m16 = ir.SignExtendWordToLong(ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32)));
     const auto product = ir.LeastSignificantWord(ir.LogicalShiftRight(ir.Mul(n32, m16), ir.Imm8(16)));
-    const auto result_overflow = ir.AddWithCarry(product, ir.GetRegister(a), ir.Imm1(0));
+    const auto result = ir.AddWithCarry(product, ir.GetRegister(a), ir.Imm1(0));
 
-    ir.SetRegister(d, result_overflow.result);
-    ir.OrQFlag(result_overflow.overflow);
+    ir.SetRegister(d, result);
+    ir.OrQFlag(ir.GetOverflowFrom(result));
     return true;
 }
 
@@ -352,7 +352,7 @@ bool TranslatorVisitor::arm_SMMLA(Cond cond, Reg d, Reg a, Reg m, bool R, Reg n)
     const auto result_carry = ir.MostSignificantWord(temp);
     auto result = result_carry.result;
     if (R) {
-        result = ir.AddWithCarry(result, ir.Imm32(0), result_carry.carry).result;
+        result = ir.AddWithCarry(result, ir.Imm32(0), result_carry.carry);
     }
 
     ir.SetRegister(d, result);
@@ -376,7 +376,7 @@ bool TranslatorVisitor::arm_SMMLS(Cond cond, Reg d, Reg a, Reg m, bool R, Reg n)
     const auto result_carry = ir.MostSignificantWord(temp);
     auto result = result_carry.result;
     if (R) {
-        result = ir.AddWithCarry(result, ir.Imm32(0), result_carry.carry).result;
+        result = ir.AddWithCarry(result, ir.Imm32(0), result_carry.carry);
     }
 
     ir.SetRegister(d, result);
@@ -399,7 +399,7 @@ bool TranslatorVisitor::arm_SMMUL(Cond cond, Reg d, Reg m, bool R, Reg n) {
     const auto result_carry = ir.MostSignificantWord(product);
     auto result = result_carry.result;
     if (R) {
-        result = ir.AddWithCarry(result, ir.Imm32(0), result_carry.carry).result;
+        result = ir.AddWithCarry(result, ir.Imm32(0), result_carry.carry);
     }
 
     ir.SetRegister(d, result);
@@ -435,11 +435,11 @@ bool TranslatorVisitor::arm_SMLAD(Cond cond, Reg d, Reg a, Reg m, bool M, Reg n)
     const IR::U32 product_hi = ir.Mul(n_hi, m_hi);
     const IR::U32 addend = ir.GetRegister(a);
 
-    auto result_overflow = ir.AddWithCarry(product_lo, product_hi, ir.Imm1(0));
-    ir.OrQFlag(result_overflow.overflow);
-    result_overflow = ir.AddWithCarry(result_overflow.result, addend, ir.Imm1(0));
-    ir.SetRegister(d, result_overflow.result);
-    ir.OrQFlag(result_overflow.overflow);
+    auto result = ir.AddWithCarry(product_lo, product_hi, ir.Imm1(0));
+    ir.OrQFlag(ir.GetOverflowFrom(result));
+    result = ir.AddWithCarry(result, addend, ir.Imm1(0));
+    ir.SetRegister(d, result);
+    ir.OrQFlag(ir.GetOverflowFrom(result));
     return true;
 }
 
@@ -507,10 +507,10 @@ bool TranslatorVisitor::arm_SMLSD(Cond cond, Reg d, Reg a, Reg m, bool M, Reg n)
     const IR::U32 product_hi = ir.Mul(n_hi, m_hi);
     const IR::U32 addend = ir.GetRegister(a);
     const IR::U32 product = ir.Sub(product_lo, product_hi);
-    auto result_overflow = ir.AddWithCarry(product, addend, ir.Imm1(0));
+    auto result = ir.AddWithCarry(product, addend, ir.Imm1(0));
 
-    ir.SetRegister(d, result_overflow.result);
-    ir.OrQFlag(result_overflow.overflow);
+    ir.SetRegister(d, result);
+    ir.OrQFlag(ir.GetOverflowFrom(result));
     return true;
 }
 
@@ -572,10 +572,10 @@ bool TranslatorVisitor::arm_SMUAD(Cond cond, Reg d, Reg m, bool M, Reg n) {
 
     const IR::U32 product_lo = ir.Mul(n_lo, m_lo);
     const IR::U32 product_hi = ir.Mul(n_hi, m_hi);
-    const auto result_overflow = ir.AddWithCarry(product_lo, product_hi, ir.Imm1(0));
+    const auto result = ir.AddWithCarry(product_lo, product_hi, ir.Imm1(0));
 
-    ir.SetRegister(d, result_overflow.result);
-    ir.OrQFlag(result_overflow.overflow);
+    ir.SetRegister(d, result);
+    ir.OrQFlag(ir.GetOverflowFrom(result));
     return true;
 }
 
diff --git a/src/dynarmic/frontend/A32/translate/impl/parallel.cpp b/src/dynarmic/frontend/A32/translate/impl/parallel.cpp
index 8f036c6c..921c8b12 100644
--- a/src/dynarmic/frontend/A32/translate/impl/parallel.cpp
+++ b/src/dynarmic/frontend/A32/translate/impl/parallel.cpp
@@ -194,7 +194,7 @@ bool TranslatorVisitor::arm_USADA8(Cond cond, Reg d, Reg a, Reg m, Reg n) {
 
     const auto tmp = ir.PackedAbsDiffSumS8(ir.GetRegister(n), ir.GetRegister(m));
     const auto result = ir.AddWithCarry(ir.GetRegister(a), tmp, ir.Imm1(0));
-    ir.SetRegister(d, result.result);
+    ir.SetRegister(d, result);
     return true;
 }
 
diff --git a/src/dynarmic/frontend/A32/translate/impl/thumb16.cpp b/src/dynarmic/frontend/A32/translate/impl/thumb16.cpp
index 6e2899d2..f2e2aa8c 100644
--- a/src/dynarmic/frontend/A32/translate/impl/thumb16.cpp
+++ b/src/dynarmic/frontend/A32/translate/impl/thumb16.cpp
@@ -62,12 +62,9 @@ bool TranslatorVisitor::thumb16_ASR_imm(Imm<5> imm5, Reg m, Reg d) {
 bool TranslatorVisitor::thumb16_ADD_reg_t1(Reg m, Reg n, Reg d) {
     const auto result = ir.AddWithCarry(ir.GetRegister(n), ir.GetRegister(m), ir.Imm1(0));
 
-    ir.SetRegister(d, result.result);
+    ir.SetRegister(d, result);
     if (!ir.current_location.IT().IsInITBlock()) {
-        ir.SetNFlag(ir.MostSignificantBit(result.result));
-        ir.SetZFlag(ir.IsZero(result.result));
-        ir.SetCFlag(result.carry);
-        ir.SetVFlag(result.overflow);
+        ir.SetCpsrNZCV(ir.NZCVFrom(result));
     }
     return true;
 }
@@ -93,12 +90,9 @@ bool TranslatorVisitor::thumb16_ADD_imm_t1(Imm<3> imm3, Reg n, Reg d) {
     const u32 imm32 = imm3.ZeroExtend();
     const auto result = ir.AddWithCarry(ir.GetRegister(n), ir.Imm32(imm32), ir.Imm1(0));
 
-    ir.SetRegister(d, result.result);
+    ir.SetRegister(d, result);
     if (!ir.current_location.IT().IsInITBlock()) {
-        ir.SetNFlag(ir.MostSignificantBit(result.result));
-        ir.SetZFlag(ir.IsZero(result.result));
-        ir.SetCFlag(result.carry);
-        ir.SetVFlag(result.overflow);
+        ir.SetCpsrNZCV(ir.NZCVFrom(result));
     }
     return true;
 }
@@ -153,12 +147,9 @@ bool TranslatorVisitor::thumb16_ADD_imm_t2(Reg d_n, Imm<8> imm8) {
     const Reg n = d_n;
     const auto result = ir.AddWithCarry(ir.GetRegister(n), ir.Imm32(imm32), ir.Imm1(0));
 
-    ir.SetRegister(d, result.result);
+    ir.SetRegister(d, result);
     if (!ir.current_location.IT().IsInITBlock()) {
-        ir.SetNFlag(ir.MostSignificantBit(result.result));
-        ir.SetZFlag(ir.IsZero(result.result));
-        ir.SetCFlag(result.carry);
-        ir.SetVFlag(result.overflow);
+        ir.SetCpsrNZCV(ir.NZCVFrom(result));
     }
     return true;
 }
@@ -270,12 +261,9 @@ bool TranslatorVisitor::thumb16_ADC_reg(Reg m, Reg d_n) {
     const auto aspr_c = ir.GetCFlag();
     const auto result = ir.AddWithCarry(ir.GetRegister(n), ir.GetRegister(m), aspr_c);
 
-    ir.SetRegister(d, result.result);
+    ir.SetRegister(d, result);
     if (!ir.current_location.IT().IsInITBlock()) {
-        ir.SetNFlag(ir.MostSignificantBit(result.result));
-        ir.SetZFlag(ir.IsZero(result.result));
-        ir.SetCFlag(result.carry);
-        ir.SetVFlag(result.overflow);
+        ir.SetCpsrNZCV(ir.NZCVFrom(result));
     }
     return true;
 }
@@ -350,10 +338,7 @@ bool TranslatorVisitor::thumb16_CMP_reg_t1(Reg m, Reg n) {
 // CMN <Rn>, <Rm>
 bool TranslatorVisitor::thumb16_CMN_reg(Reg m, Reg n) {
     const auto result = ir.AddWithCarry(ir.GetRegister(n), ir.GetRegister(m), ir.Imm1(0));
-    ir.SetNFlag(ir.MostSignificantBit(result.result));
-    ir.SetZFlag(ir.IsZero(result.result));
-    ir.SetCFlag(result.carry);
-    ir.SetVFlag(result.overflow);
+    ir.SetCpsrNZCV(ir.NZCVFrom(result));
     return true;
 }
 
@@ -430,12 +415,12 @@ bool TranslatorVisitor::thumb16_ADD_reg_t2(bool d_n_hi, Reg m, Reg d_n_lo) {
     const auto result = ir.AddWithCarry(ir.GetRegister(n), ir.GetRegister(m), ir.Imm1(0));
     if (d == Reg::PC) {
         ir.UpdateUpperLocationDescriptor();
-        ir.ALUWritePC(result.result);
+        ir.ALUWritePC(result);
         // Return to dispatch as we can't predict what PC is going to be. Stop compilation.
         ir.SetTerm(IR::Term::FastDispatchHint{});
         return false;
     } else {
-        ir.SetRegister(d, result.result);
+        ir.SetRegister(d, result);
         return true;
     }
 }
@@ -672,7 +657,7 @@ bool TranslatorVisitor::thumb16_ADD_sp_t1(Reg d, Imm<8> imm8) {
     const u32 imm32 = imm8.ZeroExtend() << 2;
     const auto result = ir.AddWithCarry(ir.GetRegister(Reg::SP), ir.Imm32(imm32), ir.Imm1(0));
 
-    ir.SetRegister(d, result.result);
+    ir.SetRegister(d, result);
     return true;
 }
 
@@ -682,7 +667,7 @@ bool TranslatorVisitor::thumb16_ADD_sp_t2(Imm<7> imm7) {
     const Reg d = Reg::SP;
     const auto result = ir.AddWithCarry(ir.GetRegister(Reg::SP), ir.Imm32(imm32), ir.Imm1(0));
 
-    ir.SetRegister(d, result.result);
+    ir.SetRegister(d, result);
     return true;
 }
 
diff --git a/src/dynarmic/frontend/A32/translate/impl/thumb32_coprocessor.cpp b/src/dynarmic/frontend/A32/translate/impl/thumb32_coprocessor.cpp
index 23cf5fa8..71f108f9 100644
--- a/src/dynarmic/frontend/A32/translate/impl/thumb32_coprocessor.cpp
+++ b/src/dynarmic/frontend/A32/translate/impl/thumb32_coprocessor.cpp
@@ -67,7 +67,7 @@ bool TranslatorVisitor::thumb32_MRC(bool two, size_t opc1, CoprocReg CRn, Reg t,
         ir.SetRegister(t, word);
     } else {
         const auto new_cpsr_nzcv = ir.And(word, ir.Imm32(0xF0000000));
-        ir.SetCpsrNZCV(new_cpsr_nzcv);
+        ir.SetCpsrNZCVRaw(new_cpsr_nzcv);
     }
     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 f7c710c7..5b5c30ba 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
@@ -166,10 +166,7 @@ bool TranslatorVisitor::thumb32_CMN_imm(Imm<1> i, Reg n, Imm<3> imm3, Imm<8> imm
     const auto imm32 = ThumbExpandImm(i, imm3, imm8);
     const auto result = ir.AddWithCarry(ir.GetRegister(n), ir.Imm32(imm32), ir.Imm1(0));
 
-    ir.SetNFlag(ir.MostSignificantBit(result.result));
-    ir.SetZFlag(ir.IsZero(result.result));
-    ir.SetCFlag(result.carry);
-    ir.SetVFlag(result.overflow);
+    ir.SetCpsrNZCV(ir.NZCVFrom(result));
     return true;
 }
 
@@ -182,12 +179,9 @@ bool TranslatorVisitor::thumb32_ADD_imm_1(Imm<1> i, bool S, Reg n, Imm<3> imm3,
     const auto imm32 = ThumbExpandImm(i, imm3, imm8);
     const auto result = ir.AddWithCarry(ir.GetRegister(n), ir.Imm32(imm32), ir.Imm1(0));
 
-    ir.SetRegister(d, result.result);
+    ir.SetRegister(d, result);
     if (S) {
-        ir.SetNFlag(ir.MostSignificantBit(result.result));
-        ir.SetZFlag(ir.IsZero(result.result));
-        ir.SetCFlag(result.carry);
-        ir.SetVFlag(result.overflow);
+        ir.SetCpsrNZCV(ir.NZCVFrom(result));
     }
     return true;
 }
@@ -200,12 +194,9 @@ bool TranslatorVisitor::thumb32_ADC_imm(Imm<1> i, bool S, Reg n, Imm<3> imm3, Re
     const auto imm32 = ThumbExpandImm(i, imm3, imm8);
     const auto result = ir.AddWithCarry(ir.GetRegister(n), ir.Imm32(imm32), ir.GetCFlag());
 
-    ir.SetRegister(d, result.result);
+    ir.SetRegister(d, result);
     if (S) {
-        ir.SetNFlag(ir.MostSignificantBit(result.result));
-        ir.SetZFlag(ir.IsZero(result.result));
-        ir.SetCFlag(result.carry);
-        ir.SetVFlag(result.overflow);
+        ir.SetCpsrNZCV(ir.NZCVFrom(result));
     }
     return true;
 }
diff --git a/src/dynarmic/frontend/A32/translate/impl/thumb32_data_processing_plain_binary_immediate.cpp b/src/dynarmic/frontend/A32/translate/impl/thumb32_data_processing_plain_binary_immediate.cpp
index ffe5e56d..d836cad9 100644
--- a/src/dynarmic/frontend/A32/translate/impl/thumb32_data_processing_plain_binary_immediate.cpp
+++ b/src/dynarmic/frontend/A32/translate/impl/thumb32_data_processing_plain_binary_immediate.cpp
@@ -85,7 +85,7 @@ bool TranslatorVisitor::thumb32_ADD_imm_2(Imm<1> imm1, Reg n, Imm<3> imm3, Reg d
     const auto reg_n = ir.GetRegister(n);
     const auto result = ir.AddWithCarry(reg_n, ir.Imm32(imm), ir.Imm1(0));
 
-    ir.SetRegister(d, result.result);
+    ir.SetRegister(d, result);
     return true;
 }
 
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 82a25fad..13c84c5c 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
@@ -178,10 +178,7 @@ bool TranslatorVisitor::thumb32_CMN_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.AddWithCarry(ir.GetRegister(n), shifted.result, ir.Imm1(0));
 
-    ir.SetNFlag(ir.MostSignificantBit(result.result));
-    ir.SetZFlag(ir.IsZero(result.result));
-    ir.SetCFlag(result.carry);
-    ir.SetVFlag(result.overflow);
+    ir.SetCpsrNZCV(ir.NZCVFrom(result));
     return true;
 }
 
@@ -194,12 +191,9 @@ bool TranslatorVisitor::thumb32_ADD_reg(bool S, Reg n, Imm<3> imm3, Reg d, Imm<2
 
     const auto shifted = EmitImmShift(ir.GetRegister(m), type, imm3, imm2, ir.GetCFlag());
     const auto result = ir.AddWithCarry(ir.GetRegister(n), shifted.result, ir.Imm1(0));
-    ir.SetRegister(d, result.result);
+    ir.SetRegister(d, result);
     if (S) {
-        ir.SetNFlag(ir.MostSignificantBit(result.result));
-        ir.SetZFlag(ir.IsZero(result.result));
-        ir.SetCFlag(result.carry);
-        ir.SetVFlag(result.overflow);
+        ir.SetCpsrNZCV(ir.NZCVFrom(result));
     }
     return true;
 }
@@ -211,12 +205,9 @@ bool TranslatorVisitor::thumb32_ADC_reg(bool S, Reg n, Imm<3> imm3, Reg d, Imm<2
 
     const auto shifted = EmitImmShift(ir.GetRegister(m), type, imm3, imm2, ir.GetCFlag());
     const auto result = ir.AddWithCarry(ir.GetRegister(n), shifted.result, ir.GetCFlag());
-    ir.SetRegister(d, result.result);
+    ir.SetRegister(d, result);
     if (S) {
-        ir.SetNFlag(ir.MostSignificantBit(result.result));
-        ir.SetZFlag(ir.IsZero(result.result));
-        ir.SetCFlag(result.carry);
-        ir.SetVFlag(result.overflow);
+        ir.SetCpsrNZCV(ir.NZCVFrom(result));
     }
     return true;
 }
diff --git a/src/dynarmic/frontend/A32/translate/impl/thumb32_multiply.cpp b/src/dynarmic/frontend/A32/translate/impl/thumb32_multiply.cpp
index bcbcf73c..6db559d1 100644
--- a/src/dynarmic/frontend/A32/translate/impl/thumb32_multiply.cpp
+++ b/src/dynarmic/frontend/A32/translate/impl/thumb32_multiply.cpp
@@ -68,12 +68,12 @@ bool TranslatorVisitor::thumb32_SMLAD(Reg n, Reg a, Reg d, bool X, Reg m) {
     const IR::U32 product_hi = ir.Mul(n_hi, m_hi);
     const IR::U32 addend = ir.GetRegister(a);
 
-    auto result_overflow = ir.AddWithCarry(product_lo, product_hi, ir.Imm1(0));
-    ir.OrQFlag(result_overflow.overflow);
-    result_overflow = ir.AddWithCarry(result_overflow.result, addend, ir.Imm1(0));
+    auto result = ir.AddWithCarry(product_lo, product_hi, ir.Imm1(0));
+    ir.OrQFlag(ir.GetOverflowFrom(result));
+    result = ir.AddWithCarry(result, addend, ir.Imm1(0));
 
-    ir.SetRegister(d, result_overflow.result);
-    ir.OrQFlag(result_overflow.overflow);
+    ir.SetRegister(d, result);
+    ir.OrQFlag(ir.GetOverflowFrom(result));
     return true;
 }
 
@@ -97,10 +97,10 @@ bool TranslatorVisitor::thumb32_SMLSD(Reg n, Reg a, Reg d, bool X, Reg m) {
     const IR::U32 product_hi = ir.Mul(n_hi, m_hi);
     const IR::U32 addend = ir.GetRegister(a);
     const IR::U32 product = ir.Sub(product_lo, product_hi);
-    auto result_overflow = ir.AddWithCarry(product, addend, ir.Imm1(0));
+    auto result = ir.AddWithCarry(product, addend, ir.Imm1(0));
 
-    ir.SetRegister(d, result_overflow.result);
-    ir.OrQFlag(result_overflow.overflow);
+    ir.SetRegister(d, result);
+    ir.OrQFlag(ir.GetOverflowFrom(result));
     return true;
 }
 
@@ -116,10 +116,10 @@ bool TranslatorVisitor::thumb32_SMLAXY(Reg n, Reg a, Reg d, bool N, bool M, Reg
     const IR::U32 m16 = M ? ir.ArithmeticShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result
                           : ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32));
     const IR::U32 product = ir.Mul(n16, m16);
-    const auto result_overflow = ir.AddWithCarry(product, ir.GetRegister(a), ir.Imm1(0));
+    const auto result = ir.AddWithCarry(product, ir.GetRegister(a), ir.Imm1(0));
 
-    ir.SetRegister(d, result_overflow.result);
-    ir.OrQFlag(result_overflow.overflow);
+    ir.SetRegister(d, result);
+    ir.OrQFlag(ir.GetOverflowFrom(result));
     return true;
 }
 
@@ -135,7 +135,7 @@ bool TranslatorVisitor::thumb32_SMMLA(Reg n, Reg a, Reg d, bool R, Reg m) {
     const auto result_carry = ir.MostSignificantWord(temp);
     auto result = result_carry.result;
     if (R) {
-        result = ir.AddWithCarry(result, ir.Imm32(0), result_carry.carry).result;
+        result = ir.AddWithCarry(result, ir.Imm32(0), result_carry.carry);
     }
 
     ir.SetRegister(d, result);
@@ -154,7 +154,7 @@ bool TranslatorVisitor::thumb32_SMMLS(Reg n, Reg a, Reg d, bool R, Reg m) {
     const auto result_carry = ir.MostSignificantWord(temp);
     auto result = result_carry.result;
     if (R) {
-        result = ir.AddWithCarry(result, ir.Imm32(0), result_carry.carry).result;
+        result = ir.AddWithCarry(result, ir.Imm32(0), result_carry.carry);
     }
 
     ir.SetRegister(d, result);
@@ -172,7 +172,7 @@ bool TranslatorVisitor::thumb32_SMMUL(Reg n, Reg d, bool R, Reg m) {
     const auto result_carry = ir.MostSignificantWord(product);
     auto result = result_carry.result;
     if (R) {
-        result = ir.AddWithCarry(result, ir.Imm32(0), result_carry.carry).result;
+        result = ir.AddWithCarry(result, ir.Imm32(0), result_carry.carry);
     }
 
     ir.SetRegister(d, result);
@@ -197,10 +197,10 @@ bool TranslatorVisitor::thumb32_SMUAD(Reg n, Reg d, bool M, Reg m) {
 
     const IR::U32 product_lo = ir.Mul(n_lo, m_lo);
     const IR::U32 product_hi = ir.Mul(n_hi, m_hi);
-    const auto result_overflow = ir.AddWithCarry(product_lo, product_hi, ir.Imm1(0));
+    const auto result = ir.AddWithCarry(product_lo, product_hi, ir.Imm1(0));
 
-    ir.SetRegister(d, result_overflow.result);
-    ir.OrQFlag(result_overflow.overflow);
+    ir.SetRegister(d, result);
+    ir.OrQFlag(ir.GetOverflowFrom(result));
     return true;
 }
 
@@ -257,10 +257,10 @@ bool TranslatorVisitor::thumb32_SMLAWY(Reg n, Reg a, Reg d, bool M, Reg m) {
     }
     const IR::U64 m16 = ir.SignExtendWordToLong(ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32)));
     const auto product = ir.LeastSignificantWord(ir.LogicalShiftRight(ir.Mul(n32, m16), ir.Imm8(16)));
-    const auto result_overflow = ir.AddWithCarry(product, ir.GetRegister(a), ir.Imm1(0));
+    const auto result = ir.AddWithCarry(product, ir.GetRegister(a), ir.Imm1(0));
 
-    ir.SetRegister(d, result_overflow.result);
-    ir.OrQFlag(result_overflow.overflow);
+    ir.SetRegister(d, result);
+    ir.OrQFlag(ir.GetOverflowFrom(result));
     return true;
 }
 
@@ -305,7 +305,7 @@ bool TranslatorVisitor::thumb32_USADA8(Reg n, Reg a, Reg d, Reg m) {
     const auto tmp = ir.PackedAbsDiffSumS8(reg_n, reg_m);
     const auto result = ir.AddWithCarry(reg_a, tmp, ir.Imm1(0));
 
-    ir.SetRegister(d, result.result);
+    ir.SetRegister(d, result);
     return true;
 }
 
diff --git a/src/dynarmic/frontend/A32/translate/impl/vfp.cpp b/src/dynarmic/frontend/A32/translate/impl/vfp.cpp
index c3622533..0ca54108 100644
--- a/src/dynarmic/frontend/A32/translate/impl/vfp.cpp
+++ b/src/dynarmic/frontend/A32/translate/impl/vfp.cpp
@@ -1155,7 +1155,7 @@ bool TranslatorVisitor::vfp_VMRS(Cond cond, Reg t) {
     if (t == Reg::R15) {
         // This encodes ASPR_nzcv access
         const auto nzcv = ir.GetFpscrNZCV();
-        ir.SetCpsrNZCV(nzcv);
+        ir.SetCpsrNZCVRaw(nzcv);
     } else {
         ir.SetRegister(t, ir.GetFpscr());
     }
diff --git a/src/dynarmic/ir/ir_emitter.cpp b/src/dynarmic/ir/ir_emitter.cpp
index 2f289d67..66591c50 100644
--- a/src/dynarmic/ir/ir_emitter.cpp
+++ b/src/dynarmic/ir/ir_emitter.cpp
@@ -240,13 +240,6 @@ U32U64 IREmitter::RotateRightMasked(const U32U64& value_in, const U32U64& shift_
     }
 }
 
-ResultAndCarryAndOverflow<U32> IREmitter::AddWithCarry(const U32& a, const U32& b, const U1& carry_in) {
-    const auto result = Inst<U32>(Opcode::Add32, a, b, carry_in);
-    const auto carry_out = Inst<U1>(Opcode::GetCarryFromOp, result);
-    const auto overflow = Inst<U1>(Opcode::GetOverflowFromOp, result);
-    return {result, carry_out, overflow};
-}
-
 U32U64 IREmitter::AddWithCarry(const U32U64& a, const U32U64& b, const U1& carry_in) {
     ASSERT(a.GetType() == b.GetType());
     if (a.GetType() == Type::U32) {
diff --git a/src/dynarmic/ir/ir_emitter.h b/src/dynarmic/ir/ir_emitter.h
index caba937d..12c489d1 100644
--- a/src/dynarmic/ir/ir_emitter.h
+++ b/src/dynarmic/ir/ir_emitter.h
@@ -134,7 +134,6 @@ public:
     U32U64 ArithmeticShiftRightMasked(const U32U64& value_in, const U32U64& shift_amount);
     U32U64 RotateRightMasked(const U32U64& value_in, const U32U64& shift_amount);
     ResultAndCarry<U32> RotateRightExtended(const U32& value_in, const U1& carry_in);
-    ResultAndCarryAndOverflow<U32> AddWithCarry(const U32& a, const U32& b, const U1& carry_in);
     ResultAndCarryAndOverflow<U32> SubWithCarry(const U32& a, const U32& b, const U1& carry_in);
     U32U64 AddWithCarry(const U32U64& a, const U32U64& b, const U1& carry_in);
     U32U64 SubWithCarry(const U32U64& a, const U32U64& b, const U1& carry_in);
diff --git a/src/dynarmic/ir/microinstruction.cpp b/src/dynarmic/ir/microinstruction.cpp
index a499c327..858c5bc2 100644
--- a/src/dynarmic/ir/microinstruction.cpp
+++ b/src/dynarmic/ir/microinstruction.cpp
@@ -176,6 +176,7 @@ bool Inst::ReadsFromCPSR() const {
 bool Inst::WritesToCPSR() const {
     switch (op) {
     case Opcode::A32SetCpsr:
+    case Opcode::A32SetCpsrNZCVRaw:
     case Opcode::A32SetCpsrNZCV:
     case Opcode::A32SetCpsrNZCVQ:
     case Opcode::A32SetNFlag:
diff --git a/src/dynarmic/ir/opcodes.inc b/src/dynarmic/ir/opcodes.inc
index f8995b19..be0cda9e 100644
--- a/src/dynarmic/ir/opcodes.inc
+++ b/src/dynarmic/ir/opcodes.inc
@@ -17,7 +17,8 @@ A32OPC(SetExtendedRegister64,                               Void,           A32E
 A32OPC(SetVector,                                           Void,           A32ExtReg,      U128                                            )
 A32OPC(GetCpsr,                                             U32,                                                                            )
 A32OPC(SetCpsr,                                             Void,           U32                                                             )
-A32OPC(SetCpsrNZCV,                                         Void,           U32                                                             )
+A32OPC(SetCpsrNZCV,                                         Void,           NZCV                                                            )
+A32OPC(SetCpsrNZCVRaw,                                      Void,           U32                                                             )
 A32OPC(SetCpsrNZCVQ,                                        Void,           U32                                                             )
 A32OPC(GetNFlag,                                            U1,                                                                             )
 A32OPC(SetNFlag,                                            Void,           U1                                                              )