From 0fdb855a11552d865beca9ba647502e53cf63ce1 Mon Sep 17 00:00:00 2001 From: Wunkolo Date: Sun, 2 Jan 2022 16:16:14 -0800 Subject: [PATCH] [JIT, x64] Add and implement `OPCODE_AND_NOT` Verified the x64 implementation using `xenia-cpu-ppc-tests`. --- src/xenia/cpu/backend/x64/x64_sequences.cc | 74 ++++++++++++++++++++++ src/xenia/cpu/hir/hir_builder.cc | 20 ++++++ src/xenia/cpu/hir/hir_builder.h | 1 + src/xenia/cpu/hir/opcodes.h | 1 + src/xenia/cpu/hir/opcodes.inl | 6 ++ src/xenia/cpu/ppc/ppc_emit_altivec.cc | 6 +- src/xenia/cpu/ppc/ppc_emit_alu.cc | 2 +- 7 files changed, 106 insertions(+), 4 deletions(-) diff --git a/src/xenia/cpu/backend/x64/x64_sequences.cc b/src/xenia/cpu/backend/x64/x64_sequences.cc index 37a05c60b..90471b248 100644 --- a/src/xenia/cpu/backend/x64/x64_sequences.cc +++ b/src/xenia/cpu/backend/x64/x64_sequences.cc @@ -2627,6 +2627,80 @@ struct AND_V128 : Sequence> { }; EMITTER_OPCODE_TABLE(OPCODE_AND, AND_I8, AND_I16, AND_I32, AND_I64, AND_V128); +// ============================================================================ +// OPCODE_AND_NOT +// ============================================================================ +template +void EmitAndNotXX(X64Emitter& e, const ARGS& i) { + if (i.src1.is_constant) { + if (i.src2.is_constant) { + // Both constants. + e.mov(i.dest, i.src1.constant() & ~i.src2.constant()); + } else { + // src1 constant. + e.mov(i.dest, i.src2.constant()); + e.not_(i.dest); + e.and_(i.dest, i.src1); + } + } else if (i.src2.is_constant) { + // src2 constant. + if (i.dest == i.src1) { + auto temp = GetTempReg(e); + e.mov(temp, ~i.src2.constant()); + e.and_(i.dest, temp); + } else { + e.mov(i.dest, i.src1); + auto temp = GetTempReg(e); + e.mov(temp, ~i.src2.constant()); + e.and_(i.dest, temp); + } + } else { + // neither are constant + if (i.dest == i.src2) { + e.not_(i.dest); + e.and_(i.dest, i.src1); + } else { + e.mov(i.dest, i.src2); + e.not_(i.dest); + e.and_(i.dest, i.src1); + } + } +} +struct AND_NOT_I8 : Sequence> { + static void Emit(X64Emitter& e, const EmitArgType& i) { + EmitAndNotXX(e, i); + } +}; +struct AND_NOT_I16 + : Sequence> { + static void Emit(X64Emitter& e, const EmitArgType& i) { + EmitAndNotXX(e, i); + } +}; +struct AND_NOT_I32 + : Sequence> { + static void Emit(X64Emitter& e, const EmitArgType& i) { + EmitAndNotXX(e, i); + } +}; +struct AND_NOT_I64 + : Sequence> { + static void Emit(X64Emitter& e, const EmitArgType& i) { + EmitAndNotXX(e, i); + } +}; +struct AND_NOT_V128 + : Sequence> { + static void Emit(X64Emitter& e, const EmitArgType& i) { + EmitCommutativeBinaryXmmOp(e, i, + [](X64Emitter& e, Xmm dest, Xmm src1, Xmm src2) { + e.vpandn(dest, src2, src1); + }); + } +}; +EMITTER_OPCODE_TABLE(OPCODE_AND_NOT, AND_NOT_I8, AND_NOT_I16, AND_NOT_I32, + AND_NOT_I64, AND_NOT_V128); + // ============================================================================ // OPCODE_OR // ============================================================================ diff --git a/src/xenia/cpu/hir/hir_builder.cc b/src/xenia/cpu/hir/hir_builder.cc index fc64b7c2e..3cc2c9aaa 100644 --- a/src/xenia/cpu/hir/hir_builder.cc +++ b/src/xenia/cpu/hir/hir_builder.cc @@ -1759,6 +1759,26 @@ Value* HIRBuilder::And(Value* value1, Value* value2) { return i->dest; } +Value* HIRBuilder::AndNot(Value* value1, Value* value2) { + ASSERT_NON_FLOAT_TYPE(value1); + ASSERT_NON_FLOAT_TYPE(value2); + ASSERT_TYPES_EQUAL(value1, value2); + + if (value1 == value2) { + return LoadZero(value1->type); + } else if (value1->IsConstantZero()) { + return value1; + } else if (value2->IsConstantZero()) { + return value1; + } + + Instr* i = AppendInstr(OPCODE_AND_NOT_info, 0, AllocValue(value1->type)); + i->set_src1(value1); + i->set_src2(value2); + i->src3.value = NULL; + return i->dest; +} + Value* HIRBuilder::Or(Value* value1, Value* value2) { ASSERT_NON_FLOAT_TYPE(value1); ASSERT_NON_FLOAT_TYPE(value2); diff --git a/src/xenia/cpu/hir/hir_builder.h b/src/xenia/cpu/hir/hir_builder.h index 81c406c12..b2809d5d8 100644 --- a/src/xenia/cpu/hir/hir_builder.h +++ b/src/xenia/cpu/hir/hir_builder.h @@ -224,6 +224,7 @@ class HIRBuilder { Value* DotProduct4(Value* value1, Value* value2); Value* And(Value* value1, Value* value2); + Value* AndNot(Value* value1, Value* value2); Value* Or(Value* value1, Value* value2); Value* Xor(Value* value1, Value* value2); Value* Not(Value* value); diff --git a/src/xenia/cpu/hir/opcodes.h b/src/xenia/cpu/hir/opcodes.h index 1649ec9dc..6f45bb8da 100644 --- a/src/xenia/cpu/hir/opcodes.h +++ b/src/xenia/cpu/hir/opcodes.h @@ -255,6 +255,7 @@ enum Opcode { OPCODE_DOT_PRODUCT_3, OPCODE_DOT_PRODUCT_4, OPCODE_AND, + OPCODE_AND_NOT, OPCODE_OR, OPCODE_XOR, OPCODE_NOT, diff --git a/src/xenia/cpu/hir/opcodes.inl b/src/xenia/cpu/hir/opcodes.inl index 9ee033aa5..584b0ac55 100644 --- a/src/xenia/cpu/hir/opcodes.inl +++ b/src/xenia/cpu/hir/opcodes.inl @@ -524,6 +524,12 @@ DEFINE_OPCODE( OPCODE_SIG_V_V_V, OPCODE_FLAG_COMMUNATIVE) +DEFINE_OPCODE( + OPCODE_AND_NOT, + "and_not", + OPCODE_SIG_V_V_V, + 0) + DEFINE_OPCODE( OPCODE_OR, "or", diff --git a/src/xenia/cpu/ppc/ppc_emit_altivec.cc b/src/xenia/cpu/ppc/ppc_emit_altivec.cc index 93f4df2b7..331713f10 100644 --- a/src/xenia/cpu/ppc/ppc_emit_altivec.cc +++ b/src/xenia/cpu/ppc/ppc_emit_altivec.cc @@ -286,7 +286,7 @@ int InstrEmit_stvlx_(PPCHIRBuilder& f, const InstrData& i, uint32_t vd, // mask = FFFF... >> eb Value* mask = f.Permute(f.LoadVectorShr(eb), f.LoadZeroVec128(), f.Not(f.LoadZeroVec128()), INT8_TYPE); - Value* v = f.Or(f.And(old_value, f.Not(mask)), f.And(new_value, mask)); + Value* v = f.Or(f.AndNot(old_value, mask), f.And(new_value, mask)); // ea &= ~0xF (handled above) f.Store(ea, f.ByteSwap(v)); return 0; @@ -328,7 +328,7 @@ int InstrEmit_stvrx_(PPCHIRBuilder& f, const InstrData& i, uint32_t vd, // mask = ~FFFF... >> eb Value* mask = f.Permute(f.LoadVectorShr(eb), f.Not(f.LoadZeroVec128()), f.LoadZeroVec128(), INT8_TYPE); - Value* v = f.Or(f.And(old_value, f.Not(mask)), f.And(new_value, mask)); + Value* v = f.Or(f.AndNot(old_value, mask), f.And(new_value, mask)); // ea &= ~0xF (handled above) f.Store(ea, f.ByteSwap(v)); f.MarkLabel(skip_label); @@ -459,7 +459,7 @@ int InstrEmit_vand128(PPCHIRBuilder& f, const InstrData& i) { int InstrEmit_vandc_(PPCHIRBuilder& f, uint32_t vd, uint32_t va, uint32_t vb) { // VD <- (VA) & ¬(VB) - Value* v = f.And(f.LoadVR(va), f.Not(f.LoadVR(vb))); + Value* v = f.AndNot(f.LoadVR(va), f.LoadVR(vb)); f.StoreVR(vd, v); return 0; } diff --git a/src/xenia/cpu/ppc/ppc_emit_alu.cc b/src/xenia/cpu/ppc/ppc_emit_alu.cc index 78f51b106..4be752936 100644 --- a/src/xenia/cpu/ppc/ppc_emit_alu.cc +++ b/src/xenia/cpu/ppc/ppc_emit_alu.cc @@ -657,7 +657,7 @@ int InstrEmit_andx(PPCHIRBuilder& f, const InstrData& i) { int InstrEmit_andcx(PPCHIRBuilder& f, const InstrData& i) { // RA <- (RS) & ¬(RB) - Value* ra = f.And(f.LoadGPR(i.X.RT), f.Not(f.LoadGPR(i.X.RB))); + Value* ra = f.AndNot(f.LoadGPR(i.X.RT), f.LoadGPR(i.X.RB)); f.StoreGPR(i.X.RA, ra); if (i.X.Rc) { f.UpdateCR(0, ra);