[JIT, x64] Add and implement `OPCODE_AND_NOT`

Verified the x64 implementation using `xenia-cpu-ppc-tests`.
This commit is contained in:
Wunkolo 2022-01-02 16:16:14 -08:00 committed by Rick Gibbed
parent 4f258b2ee9
commit 0fdb855a11
7 changed files with 106 additions and 4 deletions

View File

@ -2627,6 +2627,80 @@ struct AND_V128 : Sequence<AND_V128, I<OPCODE_AND, V128Op, V128Op, V128Op>> {
}; };
EMITTER_OPCODE_TABLE(OPCODE_AND, AND_I8, AND_I16, AND_I32, AND_I64, AND_V128); EMITTER_OPCODE_TABLE(OPCODE_AND, AND_I8, AND_I16, AND_I32, AND_I64, AND_V128);
// ============================================================================
// OPCODE_AND_NOT
// ============================================================================
template <typename SEQ, typename REG, typename ARGS>
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<typename decltype(i.src2)::reg_type>(e);
e.mov(temp, ~i.src2.constant());
e.and_(i.dest, temp);
} else {
e.mov(i.dest, i.src1);
auto temp = GetTempReg<typename decltype(i.src2)::reg_type>(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<AND_NOT_I8, I<OPCODE_AND_NOT, I8Op, I8Op, I8Op>> {
static void Emit(X64Emitter& e, const EmitArgType& i) {
EmitAndNotXX<AND_NOT_I8, Reg8>(e, i);
}
};
struct AND_NOT_I16
: Sequence<AND_NOT_I16, I<OPCODE_AND_NOT, I16Op, I16Op, I16Op>> {
static void Emit(X64Emitter& e, const EmitArgType& i) {
EmitAndNotXX<AND_NOT_I16, Reg16>(e, i);
}
};
struct AND_NOT_I32
: Sequence<AND_NOT_I32, I<OPCODE_AND_NOT, I32Op, I32Op, I32Op>> {
static void Emit(X64Emitter& e, const EmitArgType& i) {
EmitAndNotXX<AND_NOT_I32, Reg32>(e, i);
}
};
struct AND_NOT_I64
: Sequence<AND_NOT_I64, I<OPCODE_AND_NOT, I64Op, I64Op, I64Op>> {
static void Emit(X64Emitter& e, const EmitArgType& i) {
EmitAndNotXX<AND_NOT_I64, Reg64>(e, i);
}
};
struct AND_NOT_V128
: Sequence<AND_NOT_V128, I<OPCODE_AND_NOT, V128Op, V128Op, V128Op>> {
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 // OPCODE_OR
// ============================================================================ // ============================================================================

View File

@ -1759,6 +1759,26 @@ Value* HIRBuilder::And(Value* value1, Value* value2) {
return i->dest; 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) { Value* HIRBuilder::Or(Value* value1, Value* value2) {
ASSERT_NON_FLOAT_TYPE(value1); ASSERT_NON_FLOAT_TYPE(value1);
ASSERT_NON_FLOAT_TYPE(value2); ASSERT_NON_FLOAT_TYPE(value2);

View File

@ -224,6 +224,7 @@ class HIRBuilder {
Value* DotProduct4(Value* value1, Value* value2); Value* DotProduct4(Value* value1, Value* value2);
Value* And(Value* value1, Value* value2); Value* And(Value* value1, Value* value2);
Value* AndNot(Value* value1, Value* value2);
Value* Or(Value* value1, Value* value2); Value* Or(Value* value1, Value* value2);
Value* Xor(Value* value1, Value* value2); Value* Xor(Value* value1, Value* value2);
Value* Not(Value* value); Value* Not(Value* value);

View File

@ -255,6 +255,7 @@ enum Opcode {
OPCODE_DOT_PRODUCT_3, OPCODE_DOT_PRODUCT_3,
OPCODE_DOT_PRODUCT_4, OPCODE_DOT_PRODUCT_4,
OPCODE_AND, OPCODE_AND,
OPCODE_AND_NOT,
OPCODE_OR, OPCODE_OR,
OPCODE_XOR, OPCODE_XOR,
OPCODE_NOT, OPCODE_NOT,

View File

@ -524,6 +524,12 @@ DEFINE_OPCODE(
OPCODE_SIG_V_V_V, OPCODE_SIG_V_V_V,
OPCODE_FLAG_COMMUNATIVE) OPCODE_FLAG_COMMUNATIVE)
DEFINE_OPCODE(
OPCODE_AND_NOT,
"and_not",
OPCODE_SIG_V_V_V,
0)
DEFINE_OPCODE( DEFINE_OPCODE(
OPCODE_OR, OPCODE_OR,
"or", "or",

View File

@ -286,7 +286,7 @@ int InstrEmit_stvlx_(PPCHIRBuilder& f, const InstrData& i, uint32_t vd,
// mask = FFFF... >> eb // mask = FFFF... >> eb
Value* mask = f.Permute(f.LoadVectorShr(eb), f.LoadZeroVec128(), Value* mask = f.Permute(f.LoadVectorShr(eb), f.LoadZeroVec128(),
f.Not(f.LoadZeroVec128()), INT8_TYPE); 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) // ea &= ~0xF (handled above)
f.Store(ea, f.ByteSwap(v)); f.Store(ea, f.ByteSwap(v));
return 0; return 0;
@ -328,7 +328,7 @@ int InstrEmit_stvrx_(PPCHIRBuilder& f, const InstrData& i, uint32_t vd,
// mask = ~FFFF... >> eb // mask = ~FFFF... >> eb
Value* mask = f.Permute(f.LoadVectorShr(eb), f.Not(f.LoadZeroVec128()), Value* mask = f.Permute(f.LoadVectorShr(eb), f.Not(f.LoadZeroVec128()),
f.LoadZeroVec128(), INT8_TYPE); 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) // ea &= ~0xF (handled above)
f.Store(ea, f.ByteSwap(v)); f.Store(ea, f.ByteSwap(v));
f.MarkLabel(skip_label); 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) { int InstrEmit_vandc_(PPCHIRBuilder& f, uint32_t vd, uint32_t va, uint32_t vb) {
// VD <- (VA) & ¬(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); f.StoreVR(vd, v);
return 0; return 0;
} }

View File

@ -657,7 +657,7 @@ int InstrEmit_andx(PPCHIRBuilder& f, const InstrData& i) {
int InstrEmit_andcx(PPCHIRBuilder& f, const InstrData& i) { int InstrEmit_andcx(PPCHIRBuilder& f, const InstrData& i) {
// RA <- (RS) & ¬(RB) // 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); f.StoreGPR(i.X.RA, ra);
if (i.X.Rc) { if (i.X.Rc) {
f.UpdateCR(0, ra); f.UpdateCR(0, ra);