diff --git a/src/xenia/cpu/backend/x64/x64_sequences.cc b/src/xenia/cpu/backend/x64/x64_sequences.cc index f106fb5e5..0eb943d4b 100644 --- a/src/xenia/cpu/backend/x64/x64_sequences.cc +++ b/src/xenia/cpu/backend/x64/x64_sequences.cc @@ -2404,14 +2404,14 @@ EMITTER_OPCODE_TABLE( COMPARE_##op##_I16, \ COMPARE_##op##_I32, \ COMPARE_##op##_I64); -EMITTER_ASSOCIATIVE_COMPARE_XX(SLT, setl, setge); -EMITTER_ASSOCIATIVE_COMPARE_XX(SLE, setle, setg); -EMITTER_ASSOCIATIVE_COMPARE_XX(SGT, setg, setle); -EMITTER_ASSOCIATIVE_COMPARE_XX(SGE, setge, setl); -EMITTER_ASSOCIATIVE_COMPARE_XX(ULT, setb, setae); -EMITTER_ASSOCIATIVE_COMPARE_XX(ULE, setbe, seta); -EMITTER_ASSOCIATIVE_COMPARE_XX(UGT, seta, setbe); -EMITTER_ASSOCIATIVE_COMPARE_XX(UGE, setae, setb); +EMITTER_ASSOCIATIVE_COMPARE_XX(SLT, setl, setg); +EMITTER_ASSOCIATIVE_COMPARE_XX(SLE, setle, setge); +EMITTER_ASSOCIATIVE_COMPARE_XX(SGT, setg, setl); +EMITTER_ASSOCIATIVE_COMPARE_XX(SGE, setge, setle); +EMITTER_ASSOCIATIVE_COMPARE_XX(ULT, setb, seta); +EMITTER_ASSOCIATIVE_COMPARE_XX(ULE, setbe, setae); +EMITTER_ASSOCIATIVE_COMPARE_XX(UGT, seta, setb); +EMITTER_ASSOCIATIVE_COMPARE_XX(UGE, setae, setbe); // http://x86.renejeschke.de/html/file_module_x86_id_288.html #define EMITTER_ASSOCIATIVE_COMPARE_FLT_XX(op, instr) \ @@ -2449,61 +2449,6 @@ EMITTER_ASSOCIATIVE_COMPARE_FLT_XX(UGT, seta); EMITTER_ASSOCIATIVE_COMPARE_FLT_XX(UGE, setae); -// ============================================================================ -// OPCODE_DID_CARRY -// ============================================================================ -// TODO(benvanik): salc/setalc -// https://code.google.com/p/corkami/wiki/x86oddities -EMITTER(DID_CARRY_I8, MATCH(I, I8<>>)) { - static void Emit(X64Emitter& e, const EmitArgType& i) { - assert_true(!i.src1.is_constant); - e.LoadEflags(); - e.setc(i.dest); - } -}; -EMITTER(DID_CARRY_I16, MATCH(I, I16<>>)) { - static void Emit(X64Emitter& e, const EmitArgType& i) { - assert_true(!i.src1.is_constant); - e.LoadEflags(); - e.setc(i.dest); - } -}; -EMITTER(DID_CARRY_I32, MATCH(I, I32<>>)) { - static void Emit(X64Emitter& e, const EmitArgType& i) { - assert_true(!i.src1.is_constant); - e.LoadEflags(); - e.setc(i.dest); - } -}; -EMITTER(DID_CARRY_I64, MATCH(I, I64<>>)) { - static void Emit(X64Emitter& e, const EmitArgType& i) { - assert_true(!i.src1.is_constant); - e.LoadEflags(); - e.setc(i.dest); - } -}; -EMITTER_OPCODE_TABLE( - OPCODE_DID_CARRY, - DID_CARRY_I8, - DID_CARRY_I16, - DID_CARRY_I32, - DID_CARRY_I64); - - -// ============================================================================ -// OPCODE_DID_OVERFLOW -// ============================================================================ -EMITTER(DID_OVERFLOW, MATCH(I>)) { - static void Emit(X64Emitter& e, const EmitArgType& i) { - e.LoadEflags(); - e.seto(i.dest); - } -}; -EMITTER_OPCODE_TABLE( - OPCODE_DID_OVERFLOW, - DID_OVERFLOW); - - // ============================================================================ // OPCODE_DID_SATURATE // ============================================================================ @@ -2736,10 +2681,6 @@ void EmitAddXX(X64Emitter& e, const ARGS& i) { e, i, [](X64Emitter& e, const REG& dest_src, const REG& src) { e.add(dest_src, src); }, [](X64Emitter& e, const REG& dest_src, int32_t constant) { e.add(dest_src, constant); }); - if (i.instr->flags & ARITHMETIC_SET_CARRY) { - // CF is set if carried. - e.StoreEflags(); - } } EMITTER(ADD_I8, MATCH(I, I8<>, I8<>>)) { static void Emit(X64Emitter& e, const EmitArgType& i) { @@ -2817,10 +2758,6 @@ void EmitAddCarryXX(X64Emitter& e, const ARGS& i) { }, [](X64Emitter& e, const REG& dest_src, int32_t constant) { e.adc(dest_src, constant); }); - if (i.instr->flags & ARITHMETIC_SET_CARRY) { - // CF is set if carried. - e.StoreEflags(); - } } EMITTER(ADD_CARRY_I8, MATCH(I, I8<>, I8<>, I8<>>)) { static void Emit(X64Emitter& e, const EmitArgType& i) { @@ -3009,31 +2946,10 @@ EMITTER_OPCODE_TABLE( // TODO(benvanik): put dest/src1|2 together. template void EmitSubXX(X64Emitter& e, const ARGS& i) { - if (i.instr->flags & ARITHMETIC_SET_CARRY) { - // TODO(benvanik): faster way of doing sub with CF set? - SEQ::EmitAssociativeBinaryOp( - e, i, - [](X64Emitter& e, const REG& dest_src, const REG& src) { - auto temp = GetTempReg(e); - e.mov(temp, src); - e.not(temp); - e.stc(); - e.adc(dest_src, temp); - }, - [](X64Emitter& e, const REG& dest_src, int32_t constant) { - auto temp = GetTempReg(e); - e.mov(temp, constant); - e.not(temp); - e.stc(); - e.adc(dest_src, temp); - }); - e.StoreEflags(); - } else { - SEQ::EmitAssociativeBinaryOp( - e, i, - [](X64Emitter& e, const REG& dest_src, const REG& src) { e.sub(dest_src, src); }, - [](X64Emitter& e, const REG& dest_src, int32_t constant) { e.sub(dest_src, constant); }); - } + SEQ::EmitAssociativeBinaryOp( + e, i, + [](X64Emitter& e, const REG& dest_src, const REG& src) { e.sub(dest_src, src); }, + [](X64Emitter& e, const REG& dest_src, int32_t constant) { e.sub(dest_src, constant); }); } EMITTER(SUB_I8, MATCH(I, I8<>, I8<>>)) { static void Emit(X64Emitter& e, const EmitArgType& i) { @@ -6576,8 +6492,6 @@ void RegisterSequences() { REGISTER_EMITTER_OPCODE_TABLE(OPCODE_COMPARE_ULE_FLT); REGISTER_EMITTER_OPCODE_TABLE(OPCODE_COMPARE_UGT_FLT); REGISTER_EMITTER_OPCODE_TABLE(OPCODE_COMPARE_UGE_FLT); - REGISTER_EMITTER_OPCODE_TABLE(OPCODE_DID_CARRY); - REGISTER_EMITTER_OPCODE_TABLE(OPCODE_DID_OVERFLOW); REGISTER_EMITTER_OPCODE_TABLE(OPCODE_DID_SATURATE); REGISTER_EMITTER_OPCODE_TABLE(OPCODE_VECTOR_COMPARE_EQ); REGISTER_EMITTER_OPCODE_TABLE(OPCODE_VECTOR_COMPARE_SGT); diff --git a/src/xenia/cpu/compiler/passes/constant_propagation_pass.cc b/src/xenia/cpu/compiler/passes/constant_propagation_pass.cc index aa25a53bd..2923ce4b5 100644 --- a/src/xenia/cpu/compiler/passes/constant_propagation_pass.cc +++ b/src/xenia/cpu/compiler/passes/constant_propagation_pass.cc @@ -232,9 +232,9 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { case OPCODE_IS_TRUE: if (i->src1.value->IsConstant()) { if (i->src1.value->IsConstantTrue()) { - v->set_constant((int8_t)1); + v->set_constant(uint8_t(1)); } else { - v->set_constant((int8_t)0); + v->set_constant(uint8_t(0)); } i->Remove(); } @@ -242,9 +242,9 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { case OPCODE_IS_FALSE: if (i->src1.value->IsConstant()) { if (i->src1.value->IsConstantFalse()) { - v->set_constant((int8_t)1); + v->set_constant(uint8_t(1)); } else { - v->set_constant((int8_t)0); + v->set_constant(uint8_t(0)); } i->Remove(); } @@ -254,80 +254,74 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { case OPCODE_COMPARE_EQ: if (i->src1.value->IsConstant() && i->src2.value->IsConstant()) { bool value = i->src1.value->IsConstantEQ(i->src2.value); - i->dest->set_constant(value); + i->dest->set_constant(uint8_t(value)); i->Remove(); } break; case OPCODE_COMPARE_NE: if (i->src1.value->IsConstant() && i->src2.value->IsConstant()) { bool value = i->src1.value->IsConstantNE(i->src2.value); - i->dest->set_constant(value); + i->dest->set_constant(uint8_t(value)); i->Remove(); } break; case OPCODE_COMPARE_SLT: if (i->src1.value->IsConstant() && i->src2.value->IsConstant()) { bool value = i->src1.value->IsConstantSLT(i->src2.value); - i->dest->set_constant(value); + i->dest->set_constant(uint8_t(value)); i->Remove(); } break; case OPCODE_COMPARE_SLE: if (i->src1.value->IsConstant() && i->src2.value->IsConstant()) { bool value = i->src1.value->IsConstantSLE(i->src2.value); - i->dest->set_constant(value); + i->dest->set_constant(uint8_t(value)); i->Remove(); } break; case OPCODE_COMPARE_SGT: if (i->src1.value->IsConstant() && i->src2.value->IsConstant()) { bool value = i->src1.value->IsConstantSGT(i->src2.value); - i->dest->set_constant(value); + i->dest->set_constant(uint8_t(value)); i->Remove(); } break; case OPCODE_COMPARE_SGE: if (i->src1.value->IsConstant() && i->src2.value->IsConstant()) { bool value = i->src1.value->IsConstantSGE(i->src2.value); - i->dest->set_constant(value); + i->dest->set_constant(uint8_t(value)); i->Remove(); } break; case OPCODE_COMPARE_ULT: if (i->src1.value->IsConstant() && i->src2.value->IsConstant()) { bool value = i->src1.value->IsConstantULT(i->src2.value); - i->dest->set_constant(value); + i->dest->set_constant(uint8_t(value)); i->Remove(); } break; case OPCODE_COMPARE_ULE: if (i->src1.value->IsConstant() && i->src2.value->IsConstant()) { bool value = i->src1.value->IsConstantULE(i->src2.value); - i->dest->set_constant(value); + i->dest->set_constant(uint8_t(value)); i->Remove(); } break; case OPCODE_COMPARE_UGT: if (i->src1.value->IsConstant() && i->src2.value->IsConstant()) { bool value = i->src1.value->IsConstantUGT(i->src2.value); - i->dest->set_constant(value); + i->dest->set_constant(uint8_t(value)); i->Remove(); } break; case OPCODE_COMPARE_UGE: if (i->src1.value->IsConstant() && i->src2.value->IsConstant()) { bool value = i->src1.value->IsConstantUGE(i->src2.value); - i->dest->set_constant(value); + i->dest->set_constant(uint8_t(value)); i->Remove(); } break; - case OPCODE_DID_CARRY: - assert_true(!i->src1.value->IsConstant()); - break; - case OPCODE_DID_OVERFLOW: - assert_true(!i->src1.value->IsConstant()); - break; case OPCODE_DID_SATURATE: assert_true(!i->src1.value->IsConstant()); break; @@ -336,33 +330,13 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { if (i->src1.value->IsConstant() && i->src2.value->IsConstant()) { v->set_from(i->src1.value); bool did_carry = v->Add(i->src2.value); - bool propagate_carry = !!(i->flags & ARITHMETIC_SET_CARRY); i->Remove(); - - // If carry is set find the DID_CARRY and fix it. - if (propagate_carry) { - PropagateCarry(v, did_carry); - } } break; - // TODO(benvanik): ADD_CARRY (w/ ARITHMETIC_SET_CARRY) case OPCODE_ADD_CARRY: if (i->src1.value->IsConstantZero() && i->src2.value->IsConstantZero()) { Value* ca = i->src3.value; - // If carry is set find the DID_CARRY and fix it. - if (!!(i->flags & ARITHMETIC_SET_CARRY)) { - auto next = i->dest->use_head; - while (next) { - auto use = next; - next = use->next; - if (use->instr->opcode == &OPCODE_DID_CARRY_info) { - // Replace carry value. - use->instr->Replace(&OPCODE_ASSIGN_info, 0); - use->instr->set_src1(builder->LoadZero(INT8_TYPE)); - } - } - } if (ca->IsConstant()) { TypeName target_type = v->type; v->set_from(ca); @@ -383,13 +357,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { if (i->src1.value->IsConstant() && i->src2.value->IsConstant()) { v->set_from(i->src1.value); bool did_carry = v->Sub(i->src2.value); - bool propagate_carry = !!(i->flags & ARITHMETIC_SET_CARRY); i->Remove(); - - // If carry is set find the DID_CARRY and fix it. - if (propagate_carry) { - PropagateCarry(v, did_carry); - } } break; case OPCODE_MUL: @@ -535,19 +503,6 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { return true; } -void ConstantPropagationPass::PropagateCarry(Value* v, bool did_carry) { - auto next = v->use_head; - while (next) { - auto use = next; - next = use->next; - if (use->instr->opcode == &OPCODE_DID_CARRY_info) { - // Replace carry value. - use->instr->dest->set_constant(int8_t(did_carry ? 1 : 0)); - use->instr->Remove(); - } - } -} - } // namespace passes } // namespace compiler } // namespace cpu diff --git a/src/xenia/cpu/compiler/passes/constant_propagation_pass.h b/src/xenia/cpu/compiler/passes/constant_propagation_pass.h index 4f80fc471..c30228b5f 100644 --- a/src/xenia/cpu/compiler/passes/constant_propagation_pass.h +++ b/src/xenia/cpu/compiler/passes/constant_propagation_pass.h @@ -25,7 +25,6 @@ class ConstantPropagationPass : public CompilerPass { bool Run(hir::HIRBuilder* builder) override; private: - void PropagateCarry(hir::Value* v, bool did_carry); }; } // namespace passes diff --git a/src/xenia/cpu/frontend/ppc_emit_alu.cc b/src/xenia/cpu/frontend/ppc_emit_alu.cc index c5f07b572..320003315 100644 --- a/src/xenia/cpu/frontend/ppc_emit_alu.cc +++ b/src/xenia/cpu/frontend/ppc_emit_alu.cc @@ -24,6 +24,27 @@ using xe::cpu::hir::Value; // Integer arithmetic (A-3) +Value* AddDidCarry(PPCHIRBuilder& f, Value* v1, Value* v2) { + return f.CompareUGT(f.Truncate(v2, INT32_TYPE), + f.Not(f.Truncate(v1, INT32_TYPE))); +} + +Value* SubDidCarry(PPCHIRBuilder& f, Value* v1, Value* v2) { + return f.Or(f.CompareUGT(f.Truncate(v1, INT32_TYPE), + f.Not(f.Neg(f.Truncate(v2, INT32_TYPE)))), + f.IsFalse(f.Truncate(v2, INT32_TYPE))); +} + +// https://github.com/sebastianbiallas/pearpc/blob/0b3c823f61456faa677f6209545a7b906e797421/src/cpu/cpu_generic/ppc_tools.h#L26 +Value* AddWithCarryDidCarry(PPCHIRBuilder& f, Value* v1, Value* v2, Value* v3) { + v1 = f.Truncate(v1, INT32_TYPE); + v2 = f.Truncate(v2, INT32_TYPE); + assert_true(v3->type == INT8_TYPE); + v3 = f.ZeroExtend(v3, INT32_TYPE); + return f.Or(f.CompareULT(f.Add(f.Add(v1, v2), v3), v3), + f.CompareULT(f.Add(v1, v2), v1)); +} + XEEMITTER(addx, 0x7C000214, XO)(PPCHIRBuilder& f, InstrData& i) { // RD <- (RA) + (RB) Value* v = f.Add(f.LoadGPR(i.XO.RA), f.LoadGPR(i.XO.RB)); @@ -41,13 +62,15 @@ XEEMITTER(addx, 0x7C000214, XO)(PPCHIRBuilder& f, InstrData& i) { XEEMITTER(addcx, 0x7C000014, XO)(PPCHIRBuilder& f, InstrData& i) { // RD <- (RA) + (RB) // CA <- carry bit - Value* v = - f.Add(f.LoadGPR(i.XO.RA), f.LoadGPR(i.XO.RB), ARITHMETIC_SET_CARRY); - f.StoreCA(f.DidCarry(v)); + Value* ra = f.LoadGPR(i.XO.RA); + Value* rb = f.LoadGPR(i.XO.RB); + Value* v = f.Add(ra, rb); f.StoreGPR(i.XO.RT, v); if (i.XO.OE) { assert_always(); // e.update_xer_with_overflow(EFLAGS OF?); + } else { + f.StoreCA(AddDidCarry(f, ra, rb)); } if (i.XO.Rc) { f.UpdateCR(0, v); @@ -58,13 +81,15 @@ XEEMITTER(addcx, 0x7C000014, XO)(PPCHIRBuilder& f, InstrData& i) { XEEMITTER(addex, 0x7C000114, XO)(PPCHIRBuilder& f, InstrData& i) { // RD <- (RA) + (RB) + XER[CA] // CA <- carry bit - Value* v = f.AddWithCarry(f.LoadGPR(i.XO.RA), f.LoadGPR(i.XO.RB), f.LoadCA(), - ARITHMETIC_SET_CARRY); - f.StoreCA(f.DidCarry(v)); + Value* ra = f.LoadGPR(i.XO.RA); + Value* rb = f.LoadGPR(i.XO.RB); + Value* v = f.AddWithCarry(ra, rb, f.LoadCA()); f.StoreGPR(i.XO.RT, v); if (i.XO.OE) { assert_always(); // e.update_xer_with_overflow(EFLAGS OF?); + } else { + f.StoreCA(AddWithCarryDidCarry(f, ra, rb, f.LoadCA())); } if (i.XO.Rc) { f.UpdateCR(0, v); @@ -89,20 +114,20 @@ XEEMITTER(addi, 0x38000000, D)(PPCHIRBuilder& f, InstrData& i) { XEEMITTER(addic, 0x30000000, D)(PPCHIRBuilder& f, InstrData& i) { // RT <- (RA) + EXTS(SI) // CA <- carry bit - Value* v = f.Add(f.LoadGPR(i.D.RA), f.LoadConstant(XEEXTS16(i.D.DS)), - ARITHMETIC_SET_CARRY); - f.StoreCA(f.DidCarry(v)); + Value* ra = f.LoadGPR(i.D.RA); + Value* v = f.Add(ra, f.LoadConstant(XEEXTS16(i.D.DS))); f.StoreGPR(i.D.RT, v); + f.StoreCA(AddDidCarry(f, ra, f.LoadConstant(XEEXTS16(i.D.DS)))); return 0; } XEEMITTER(addicx, 0x34000000, D)(PPCHIRBuilder& f, InstrData& i) { // RT <- (RA) + EXTS(SI) // CA <- carry bit - Value* v = f.Add(f.LoadGPR(i.D.RA), f.LoadConstant(XEEXTS16(i.D.DS)), - ARITHMETIC_SET_CARRY); - f.StoreCA(f.DidCarry(v)); + Value* ra = f.LoadGPR(i.D.RA); + Value* v = f.Add(f.LoadGPR(i.D.RA), f.LoadConstant(XEEXTS16(i.D.DS))); f.StoreGPR(i.D.RT, v); + f.StoreCA(AddDidCarry(f, ra, f.LoadConstant(XEEXTS16(i.D.DS)))); f.UpdateCR(0, v); return 0; } @@ -124,17 +149,18 @@ XEEMITTER(addis, 0x3C000000, D)(PPCHIRBuilder& f, InstrData& i) { XEEMITTER(addmex, 0x7C0001D4, XO)(PPCHIRBuilder& f, InstrData& i) { // RT <- (RA) + CA - 1 // CA <- carry bit - Value* v = f.AddWithCarry(f.LoadGPR(i.XO.RA), f.LoadConstant((int64_t)-1), - f.LoadCA(), ARITHMETIC_SET_CARRY); + Value* ra = f.LoadGPR(i.XO.RA); + Value* v = f.AddWithCarry(ra, f.LoadConstant((int64_t)-1), f.LoadCA()); + f.StoreGPR(i.XO.RT, v); if (i.XO.OE) { // With XER[SO] update too. // e.update_xer_with_overflow_and_carry(b.CreateExtractValue(v, 1)); assert_always(); } else { // Just CA update. - f.StoreCA(f.DidCarry(v)); + f.StoreCA( + AddWithCarryDidCarry(f, ra, f.LoadConstant((int64_t)-1), f.LoadCA())); } - f.StoreGPR(i.XO.RT, v); if (i.XO.Rc) { f.UpdateCR(0, v); } @@ -144,17 +170,17 @@ XEEMITTER(addmex, 0x7C0001D4, XO)(PPCHIRBuilder& f, InstrData& i) { XEEMITTER(addzex, 0x7C000194, XO)(PPCHIRBuilder& f, InstrData& i) { // RT <- (RA) + CA // CA <- carry bit - Value* v = f.AddWithCarry(f.LoadGPR(i.XO.RA), f.LoadZero(INT64_TYPE), - f.LoadCA(), ARITHMETIC_SET_CARRY); + Value* ra = f.LoadGPR(i.XO.RA); + Value* v = f.AddWithCarry(ra, f.LoadZero(INT64_TYPE), f.LoadCA()); + f.StoreGPR(i.XO.RT, v); if (i.XO.OE) { // With XER[SO] update too. // e.update_xer_with_overflow_and_carry(b.CreateExtractValue(v, 1)); assert_always(); } else { // Just CA update. - f.StoreCA(f.DidCarry(v)); + f.StoreCA(AddWithCarryDidCarry(f, ra, f.LoadZero(INT64_TYPE), f.LoadCA())); } - f.StoreGPR(i.XO.RT, v); if (i.XO.Rc) { f.UpdateCR(0, v); } @@ -425,13 +451,15 @@ XEEMITTER(subfx, 0x7C000050, XO)(PPCHIRBuilder& f, InstrData& i) { XEEMITTER(subfcx, 0x7C000010, XO)(PPCHIRBuilder& f, InstrData& i) { // RT <- ¬(RA) + (RB) + 1 - Value* v = - f.Sub(f.LoadGPR(i.XO.RB), f.LoadGPR(i.XO.RA), ARITHMETIC_SET_CARRY); - f.StoreCA(f.DidCarry(v)); + Value* ra = f.LoadGPR(i.XO.RA); + Value* rb = f.LoadGPR(i.XO.RB); + Value* v = f.Sub(rb, ra); f.StoreGPR(i.XO.RT, v); if (i.XO.OE) { assert_always(); // e.update_xer_with_overflow(EFLAGS??); + } else { + f.StoreCA(SubDidCarry(f, rb, ra)); } if (i.XO.Rc) { f.UpdateCR(0, v); @@ -441,22 +469,24 @@ XEEMITTER(subfcx, 0x7C000010, XO)(PPCHIRBuilder& f, InstrData& i) { XEEMITTER(subficx, 0x20000000, D)(PPCHIRBuilder& f, InstrData& i) { // RT <- ¬(RA) + EXTS(SI) + 1 - Value* v = f.Sub(f.LoadConstant(XEEXTS16(i.D.DS)), f.LoadGPR(i.D.RA), - ARITHMETIC_SET_CARRY); - f.StoreCA(f.DidCarry(v)); + Value* ra = f.LoadGPR(i.D.RA); + Value* v = f.Sub(f.LoadConstant(XEEXTS16(i.D.DS)), ra); f.StoreGPR(i.D.RT, v); + f.StoreCA(SubDidCarry(f, f.LoadConstant(XEEXTS16(i.D.DS)), ra)); return 0; } XEEMITTER(subfex, 0x7C000110, XO)(PPCHIRBuilder& f, InstrData& i) { // RT <- ¬(RA) + (RB) + CA - Value* v = f.AddWithCarry(f.Not(f.LoadGPR(i.XO.RA)), f.LoadGPR(i.XO.RB), - f.LoadCA(), ARITHMETIC_SET_CARRY); - f.StoreCA(f.DidCarry(v)); + Value* not_ra = f.Not(f.LoadGPR(i.XO.RA)); + Value* rb = f.LoadGPR(i.XO.RB); + Value* v = f.AddWithCarry(not_ra, rb, f.LoadCA()); f.StoreGPR(i.XO.RT, v); if (i.XO.OE) { assert_always(); // e.update_xer_with_overflow_and_carry(b.CreateExtractValue(v, 1)); + } else { + f.StoreCA(AddWithCarryDidCarry(f, not_ra, rb, f.LoadCA())); } if (i.XO.Rc) { f.UpdateCR(0, v); @@ -466,16 +496,16 @@ XEEMITTER(subfex, 0x7C000110, XO)(PPCHIRBuilder& f, InstrData& i) { XEEMITTER(subfmex, 0x7C0001D0, XO)(PPCHIRBuilder& f, InstrData& i) { // RT <- ¬(RA) + CA - 1 - Value* v = - f.AddWithCarry(f.Not(f.LoadGPR(i.XO.RA)), f.LoadConstant((int64_t)-1), - f.LoadCA(), ARITHMETIC_SET_CARRY); + Value* not_ra = f.Not(f.LoadGPR(i.XO.RA)); + Value* v = f.AddWithCarry(not_ra, f.LoadConstant((int64_t)-1), f.LoadCA()); + f.StoreGPR(i.XO.RT, v); if (i.XO.OE) { assert_always(); // e.update_xer_with_overflow_and_carry(b.CreateExtractValue(v, 1)); } else { - f.StoreCA(f.DidCarry(v)); + f.StoreCA(AddWithCarryDidCarry(f, not_ra, f.LoadConstant((int64_t)-1), + f.LoadCA())); } - f.StoreGPR(i.XO.RT, v); if (i.XO.Rc) { f.UpdateCR(0, v); } @@ -484,15 +514,16 @@ XEEMITTER(subfmex, 0x7C0001D0, XO)(PPCHIRBuilder& f, InstrData& i) { XEEMITTER(subfzex, 0x7C000190, XO)(PPCHIRBuilder& f, InstrData& i) { // RT <- ¬(RA) + CA - Value* v = f.AddWithCarry(f.Not(f.LoadGPR(i.XO.RA)), f.LoadZero(INT64_TYPE), - f.LoadCA(), ARITHMETIC_SET_CARRY); + Value* not_ra = f.Not(f.LoadGPR(i.XO.RA)); + Value* v = f.AddWithCarry(not_ra, f.LoadZero(INT64_TYPE), f.LoadCA()); + f.StoreGPR(i.XO.RT, v); if (i.XO.OE) { assert_always(); // e.update_xer_with_overflow_and_carry(b.CreateExtractValue(v, 1)); } else { - f.StoreCA(f.DidCarry(v)); + f.StoreCA( + AddWithCarryDidCarry(f, not_ra, f.LoadZero(INT64_TYPE), f.LoadCA())); } - f.StoreGPR(i.XO.RT, v); if (i.XO.Rc) { f.UpdateCR(0, v); } diff --git a/src/xenia/cpu/frontend/test/instr_addc.s b/src/xenia/cpu/frontend/test/instr_addc.s index 0da20d121..7c0b64bac 100644 --- a/src/xenia/cpu/frontend/test/instr_addc.s +++ b/src/xenia/cpu/frontend/test/instr_addc.s @@ -248,7 +248,7 @@ test_addc_cr_6: #_ REGISTER_OUT r3 0x8000000000000001 #_ REGISTER_OUT r4 0x7FFFFFFFFFFFFFFF #_ REGISTER_OUT r5 2 - #_ REGISTER_OUT r6 0 + #_ REGISTER_OUT r6 1 #_ REGISTER_OUT r12 0x40000000 test_addc_cr_6_constant: @@ -262,5 +262,5 @@ test_addc_cr_6_constant: #_ REGISTER_OUT r3 0x8000000000000001 #_ REGISTER_OUT r4 0x7FFFFFFFFFFFFFFF #_ REGISTER_OUT r5 2 - #_ REGISTER_OUT r6 0 + #_ REGISTER_OUT r6 1 #_ REGISTER_OUT r12 0x40000000 diff --git a/src/xenia/cpu/frontend/test/instr_addic.s b/src/xenia/cpu/frontend/test/instr_addic.s index 5726b71d4..891745683 100644 --- a/src/xenia/cpu/frontend/test/instr_addic.s +++ b/src/xenia/cpu/frontend/test/instr_addic.s @@ -30,6 +30,23 @@ test_addic_2_constant: #_ REGISTER_OUT r4 0 #_ REGISTER_OUT r6 1 +test_addic_3: + #_ REGISTER_IN r4 0xFFFFFFFF + addic r4, r4, 1 + adde r6, r0, r0 + blr + #_ REGISTER_OUT r4 0x0000000100000000 + #_ REGISTER_OUT r6 1 + +test_addic_3_constant: + li r4, 0xFFFFFFFF + srw r4, r4, 0 + addic r4, r4, 1 + adde r6, r0, r0 + blr + #_ REGISTER_OUT r4 0x0000000100000000 + #_ REGISTER_OUT r6 1 + test_addic_cr_1: #_ REGISTER_IN r4 1 addic. r4, r4, 1 diff --git a/src/xenia/cpu/frontend/test/instr_lvexx.s b/src/xenia/cpu/frontend/test/instr_lvexx.s index eb2ba2fce..1365ab788 100644 --- a/src/xenia/cpu/frontend/test/instr_lvexx.s +++ b/src/xenia/cpu/frontend/test/instr_lvexx.s @@ -1,95 +1,95 @@ test_lvebx_1: - #_ MEMORY_IN 00000000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f - #_ REGISTER_IN r4 0 + #_ MEMORY_IN 00001000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f + #_ REGISTER_IN r4 0x00001000 lvebx v3, r0, r4 blr - #_ REGISTER_OUT r4 0 + #_ REGISTER_OUT r4 0x00001000 #_ REGISTER_OUT v3 [00010203, 04050607, 08090A0B, 0C0D0E0F] test_lvebx_1_constant: - #_ MEMORY_IN 00000000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f - li r4, 0 + #_ MEMORY_IN 00001000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f + li r4, 0x00001000 lvebx v3, r0, r4 blr - #_ REGISTER_OUT r4 0 + #_ REGISTER_OUT r4 0x00001000 #_ REGISTER_OUT v3 [00010203, 04050607, 08090A0B, 0C0D0E0F] test_lvebx_2: - #_ MEMORY_IN 00000000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f - #_ REGISTER_IN r4 4 + #_ MEMORY_IN 00001000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f + #_ REGISTER_IN r4 0x00001004 lvebx v3, r0, r4 blr - #_ REGISTER_OUT r4 4 + #_ REGISTER_OUT r4 0x00001004 #_ REGISTER_OUT v3 [00010203, 04050607, 08090A0B, 0C0D0E0F] test_lvebx_2_constant: - #_ MEMORY_IN 00000000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f - li r4, 4 + #_ MEMORY_IN 00001000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f + li r4, 0x00001004 lvebx v3, r0, r4 blr - #_ REGISTER_OUT r4 4 + #_ REGISTER_OUT r4 0x00001004 #_ REGISTER_OUT v3 [00010203, 04050607, 08090A0B, 0C0D0E0F] test_lvehx_1: - #_ MEMORY_IN 00000000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f - #_ REGISTER_IN r4 0 + #_ MEMORY_IN 00001000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f + #_ REGISTER_IN r4 0x00001000 lvehx v3, r0, r4 blr - #_ REGISTER_OUT r4 0 + #_ REGISTER_OUT r4 0x00001000 #_ REGISTER_OUT v3 [00010203, 04050607, 08090A0B, 0C0D0E0F] test_lvehx_1_constant: - #_ MEMORY_IN 00000000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f - li r4, 0 + #_ MEMORY_IN 00001000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f + li r4, 0x00001000 lvehx v3, r0, r4 blr - #_ REGISTER_OUT r4 0 + #_ REGISTER_OUT r4 0x00001000 #_ REGISTER_OUT v3 [00010203, 04050607, 08090A0B, 0C0D0E0F] test_lvehx_2: - #_ MEMORY_IN 00000000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f - #_ REGISTER_IN r4 4 + #_ MEMORY_IN 00001000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f + #_ REGISTER_IN r4 0x00001004 lvehx v3, r0, r4 blr - #_ REGISTER_OUT r4 4 + #_ REGISTER_OUT r4 0x00001004 #_ REGISTER_OUT v3 [00010203, 04050607, 08090A0B, 0C0D0E0F] test_lvehx_2_constant: - #_ MEMORY_IN 00000000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f - li r4, 4 + #_ MEMORY_IN 00001000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f + li r4, 0x00001004 lvehx v3, r0, r4 blr - #_ REGISTER_OUT r4 4 + #_ REGISTER_OUT r4 0x00001004 #_ REGISTER_OUT v3 [00010203, 04050607, 08090A0B, 0C0D0E0F] test_lvewx_1: - #_ MEMORY_IN 00000000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f - #_ REGISTER_IN r4 0 + #_ MEMORY_IN 00001000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f + #_ REGISTER_IN r4 0x00001000 lvewx v3, r0, r4 blr - #_ REGISTER_OUT r4 0 + #_ REGISTER_OUT r4 0x00001000 #_ REGISTER_OUT v3 [00010203, 04050607, 08090A0B, 0C0D0E0F] test_lvewx_1_constant: - #_ MEMORY_IN 00000000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f - li r4, 0 + #_ MEMORY_IN 00001000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f + li r4, 0x00001000 lvewx v3, r0, r4 blr - #_ REGISTER_OUT r4 0 + #_ REGISTER_OUT r4 0x00001000 #_ REGISTER_OUT v3 [00010203, 04050607, 08090A0B, 0C0D0E0F] test_lvewx_2: - #_ MEMORY_IN 00000000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f - #_ REGISTER_IN r4 4 + #_ MEMORY_IN 00001000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f + #_ REGISTER_IN r4 0x00001004 lvewx v3, r0, r4 blr - #_ REGISTER_OUT r4 4 + #_ REGISTER_OUT r4 0x00001004 #_ REGISTER_OUT v3 [00010203, 04050607, 08090A0B, 0C0D0E0F] test_lvewx_2_constant: - #_ MEMORY_IN 00000000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f - li r4, 4 + #_ MEMORY_IN 00001000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f + li r4, 0x00001004 lvewx v3, r0, r4 blr - #_ REGISTER_OUT r4 4 + #_ REGISTER_OUT r4 0x00001004 #_ REGISTER_OUT v3 [00010203, 04050607, 08090A0B, 0C0D0E0F] diff --git a/src/xenia/cpu/frontend/test/sequence_branch_carry.s b/src/xenia/cpu/frontend/test/sequence_branch_carry.s index 23ed8c0ba..844919696 100644 --- a/src/xenia/cpu/frontend/test/sequence_branch_carry.s +++ b/src/xenia/cpu/frontend/test/sequence_branch_carry.s @@ -33,7 +33,7 @@ test_equiv_2: li r12, 1 blr #_ REGISTER_OUT r7 0xffffffffffffffff - #_ REGISTER_OUT r8 0xffffffff00000000 + #_ REGISTER_OUT r8 0 #_ REGISTER_OUT r9 0xffffffff9e2a0000 #_ REGISTER_OUT r30 0xffffffff9e2a83c1 #_ REGISTER_OUT r31 0 diff --git a/src/xenia/cpu/frontend/test/xe-cpu-ppc-test.cc b/src/xenia/cpu/frontend/test/xe-cpu-ppc-test.cc index e4eb6444e..e541c840f 100644 --- a/src/xenia/cpu/frontend/test/xe-cpu-ppc-test.cc +++ b/src/xenia/cpu/frontend/test/xe-cpu-ppc-test.cc @@ -198,6 +198,11 @@ class TestRunner { processor->backend()->CommitExecutableRange(START_ADDRESS, START_ADDRESS + 1024 * 1024); + // Add dummy space for memory. + processor->memory()->LookupHeap(0)->AllocFixed( + 0x1000, 0xEFFF, 0, kMemoryAllocationReserve | kMemoryAllocationCommit, + kMemoryProtectRead | kMemoryProtectWrite); + // Simulate a thread. uint32_t stack_size = 64 * 1024; uint32_t stack_address = START_ADDRESS - stack_size; diff --git a/src/xenia/cpu/hir/hir_builder.cc b/src/xenia/cpu/hir/hir_builder.cc index 9e9f7ee7d..e23ff610f 100644 --- a/src/xenia/cpu/hir/hir_builder.cc +++ b/src/xenia/cpu/hir/hir_builder.cc @@ -1287,20 +1287,6 @@ Value* HIRBuilder::CompareUGE(Value* value1, Value* value2) { return CompareXX(OPCODE_COMPARE_UGE_info, value1, value2); } -Value* HIRBuilder::DidCarry(Value* value) { - Instr* i = AppendInstr(OPCODE_DID_CARRY_info, 0, AllocValue(INT8_TYPE)); - i->set_src1(value); - i->src2.value = i->src3.value = NULL; - return i->dest; -} - -Value* HIRBuilder::DidOverflow(Value* value) { - Instr* i = AppendInstr(OPCODE_DID_OVERFLOW_info, 0, AllocValue(INT8_TYPE)); - i->set_src1(value); - i->src2.value = i->src3.value = NULL; - return i->dest; -} - Value* HIRBuilder::DidSaturate(Value* value) { Instr* i = AppendInstr(OPCODE_DID_SATURATE_info, 0, AllocValue(INT8_TYPE)); i->set_src1(value); diff --git a/src/xenia/cpu/hir/hir_builder.h b/src/xenia/cpu/hir/hir_builder.h index 0d679cf68..c72983c14 100644 --- a/src/xenia/cpu/hir/hir_builder.h +++ b/src/xenia/cpu/hir/hir_builder.h @@ -158,8 +158,6 @@ class HIRBuilder { Value* CompareULE(Value* value1, Value* value2); Value* CompareUGT(Value* value1, Value* value2); Value* CompareUGE(Value* value1, Value* value2); - Value* DidCarry(Value* value); - Value* DidOverflow(Value* value); Value* DidSaturate(Value* value); Value* VectorCompareEQ(Value* value1, Value* value2, TypeName part_type); Value* VectorCompareSGT(Value* value1, Value* value2, TypeName part_type); diff --git a/src/xenia/cpu/hir/opcodes.h b/src/xenia/cpu/hir/opcodes.h index 4bdb53218..5af5fa7ac 100644 --- a/src/xenia/cpu/hir/opcodes.h +++ b/src/xenia/cpu/hir/opcodes.h @@ -48,7 +48,6 @@ enum PrefetchFlags { PREFETCH_STORE = (1 << 2), }; enum ArithmeticFlags { - ARITHMETIC_SET_CARRY = (1 << 1), ARITHMETIC_UNSIGNED = (1 << 2), ARITHMETIC_SATURATE = (1 << 3), }; @@ -163,8 +162,6 @@ enum Opcode { OPCODE_COMPARE_ULE, OPCODE_COMPARE_UGT, OPCODE_COMPARE_UGE, - OPCODE_DID_CARRY, - OPCODE_DID_OVERFLOW, OPCODE_DID_SATURATE, OPCODE_VECTOR_COMPARE_EQ, OPCODE_VECTOR_COMPARE_SGT, diff --git a/src/xenia/cpu/hir/opcodes.inl b/src/xenia/cpu/hir/opcodes.inl index a80a38e75..58a23f6e4 100644 --- a/src/xenia/cpu/hir/opcodes.inl +++ b/src/xenia/cpu/hir/opcodes.inl @@ -341,16 +341,6 @@ DEFINE_OPCODE( OPCODE_SIG_V_V_V, 0) -DEFINE_OPCODE( - OPCODE_DID_CARRY, - "did_carry", - OPCODE_SIG_V_V, - OPCODE_FLAG_PAIRED_PREV) -DEFINE_OPCODE( - OPCODE_DID_OVERFLOW, - "did_overflow", - OPCODE_SIG_V_V, - OPCODE_FLAG_PAIRED_PREV) DEFINE_OPCODE( OPCODE_DID_SATURATE, "did_saturate", diff --git a/src/xenia/cpu/test/test_add.cc b/src/xenia/cpu/test/test_add.cc index acff3fb10..a8a9e41ca 100644 --- a/src/xenia/cpu/test/test_add.cc +++ b/src/xenia/cpu/test/test_add.cc @@ -81,47 +81,6 @@ TEST_CASE("ADD_I8", "[instr]") { }); } -TEST_CASE("ADD_I8_CARRY", "[instr]") { - TestFunction test([](HIRBuilder& b) { - auto v = b.Add(b.Truncate(LoadGPR(b, 4), INT8_TYPE), - b.Truncate(LoadGPR(b, 5), INT8_TYPE), ARITHMETIC_SET_CARRY); - StoreGPR(b, 3, b.ZeroExtend(b.DidCarry(v), INT64_TYPE)); - b.Return(); - }); - test.Run([](PPCContext* ctx) { - ctx->r[4] = 0; - ctx->r[5] = 0; - }, - [](PPCContext* ctx) { - auto result = ctx->r[3]; - REQUIRE(result == 0); - }); - test.Run([](PPCContext* ctx) { - ctx->r[4] = UINT8_MAX; - ctx->r[5] = 1; - }, - [](PPCContext* ctx) { - auto result = ctx->r[3]; - REQUIRE(result == 1); - }); - test.Run([](PPCContext* ctx) { - ctx->r[4] = UINT8_MAX; - ctx->r[5] = UINT8_MAX; - }, - [](PPCContext* ctx) { - auto result = ctx->r[3]; - REQUIRE(result == 1); - }); - test.Run([](PPCContext* ctx) { - ctx->r[4] = INT8_MIN; - ctx->r[5] = -1; - }, - [](PPCContext* ctx) { - auto result = ctx->r[3]; - REQUIRE(result == 1); - }); -} - TEST_CASE("ADD_I16", "[instr]") { TestFunction test([](HIRBuilder& b) { StoreGPR(b, 3, b.ZeroExtend(b.Add(b.Truncate(LoadGPR(b, 4), INT16_TYPE), @@ -187,47 +146,6 @@ TEST_CASE("ADD_I16", "[instr]") { }); } -TEST_CASE("ADD_I16_CARRY", "[instr]") { - TestFunction test([](HIRBuilder& b) { - auto v = b.Add(b.Truncate(LoadGPR(b, 4), INT16_TYPE), - b.Truncate(LoadGPR(b, 5), INT16_TYPE), ARITHMETIC_SET_CARRY); - StoreGPR(b, 3, b.ZeroExtend(b.DidCarry(v), INT64_TYPE)); - b.Return(); - }); - test.Run([](PPCContext* ctx) { - ctx->r[4] = 0; - ctx->r[5] = 0; - }, - [](PPCContext* ctx) { - auto result = ctx->r[3]; - REQUIRE(result == 0); - }); - test.Run([](PPCContext* ctx) { - ctx->r[4] = UINT16_MAX; - ctx->r[5] = 1; - }, - [](PPCContext* ctx) { - auto result = ctx->r[3]; - REQUIRE(result == 1); - }); - test.Run([](PPCContext* ctx) { - ctx->r[4] = UINT16_MAX; - ctx->r[5] = UINT16_MAX; - }, - [](PPCContext* ctx) { - auto result = ctx->r[3]; - REQUIRE(result == 1); - }); - test.Run([](PPCContext* ctx) { - ctx->r[4] = INT16_MIN; - ctx->r[5] = -1; - }, - [](PPCContext* ctx) { - auto result = ctx->r[3]; - REQUIRE(result == 1); - }); -} - TEST_CASE("ADD_I32", "[instr]") { TestFunction test([](HIRBuilder& b) { StoreGPR(b, 3, b.ZeroExtend(b.Add(b.Truncate(LoadGPR(b, 4), INT32_TYPE), @@ -293,47 +211,6 @@ TEST_CASE("ADD_I32", "[instr]") { }); } -TEST_CASE("ADD_I32_CARRY", "[instr]") { - TestFunction test([](HIRBuilder& b) { - auto v = b.Add(b.Truncate(LoadGPR(b, 4), INT32_TYPE), - b.Truncate(LoadGPR(b, 5), INT32_TYPE), ARITHMETIC_SET_CARRY); - StoreGPR(b, 3, b.ZeroExtend(b.DidCarry(v), INT64_TYPE)); - b.Return(); - }); - test.Run([](PPCContext* ctx) { - ctx->r[4] = 0; - ctx->r[5] = 0; - }, - [](PPCContext* ctx) { - auto result = ctx->r[3]; - REQUIRE(result == 0); - }); - test.Run([](PPCContext* ctx) { - ctx->r[4] = UINT32_MAX; - ctx->r[5] = 1; - }, - [](PPCContext* ctx) { - auto result = ctx->r[3]; - REQUIRE(result == 1); - }); - test.Run([](PPCContext* ctx) { - ctx->r[4] = UINT32_MAX; - ctx->r[5] = UINT32_MAX; - }, - [](PPCContext* ctx) { - auto result = ctx->r[3]; - REQUIRE(result == 1); - }); - test.Run([](PPCContext* ctx) { - ctx->r[4] = INT32_MIN; - ctx->r[5] = -1; - }, - [](PPCContext* ctx) { - auto result = ctx->r[3]; - REQUIRE(result == 1); - }); -} - TEST_CASE("ADD_I64", "[instr]") { TestFunction test([](HIRBuilder& b) { StoreGPR(b, 3, b.Add(LoadGPR(b, 4), LoadGPR(b, 5))); @@ -397,47 +274,6 @@ TEST_CASE("ADD_I64", "[instr]") { }); } -TEST_CASE("ADD_I64_CARRY", "[instr]") { - TestFunction test([](HIRBuilder& b) { - auto v = b.Add(b.Truncate(LoadGPR(b, 4), INT64_TYPE), - b.Truncate(LoadGPR(b, 5), INT64_TYPE), ARITHMETIC_SET_CARRY); - StoreGPR(b, 3, b.ZeroExtend(b.DidCarry(v), INT64_TYPE)); - b.Return(); - }); - test.Run([](PPCContext* ctx) { - ctx->r[4] = 0; - ctx->r[5] = 0; - }, - [](PPCContext* ctx) { - auto result = ctx->r[3]; - REQUIRE(result == 0); - }); - test.Run([](PPCContext* ctx) { - ctx->r[4] = UINT64_MAX; - ctx->r[5] = 1; - }, - [](PPCContext* ctx) { - auto result = ctx->r[3]; - REQUIRE(result == 1); - }); - test.Run([](PPCContext* ctx) { - ctx->r[4] = UINT64_MAX; - ctx->r[5] = UINT64_MAX; - }, - [](PPCContext* ctx) { - auto result = ctx->r[3]; - REQUIRE(result == 1); - }); - test.Run([](PPCContext* ctx) { - ctx->r[4] = INT64_MIN; - ctx->r[5] = -1; - }, - [](PPCContext* ctx) { - auto result = ctx->r[3]; - REQUIRE(result == 1); - }); -} - TEST_CASE("ADD_F32", "[instr]") { TestFunction test([](HIRBuilder& b) { StoreFPR(b, 3, b.Convert(b.Add(b.Convert(LoadFPR(b, 4), FLOAT32_TYPE),