[JIT, x64] Add and implement `OPCODE_AND_NOT`
Verified the x64 implementation using `xenia-cpu-ppc-tests`.
This commit is contained in:
parent
4f258b2ee9
commit
0fdb855a11
|
@ -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);
|
||||
|
||||
// ============================================================================
|
||||
// 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
|
||||
// ============================================================================
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue