diff --git a/src/xenia/cpu/backend/x64/x64_sequences.cc b/src/xenia/cpu/backend/x64/x64_sequences.cc index 34cef4f7d..2a4262d16 100644 --- a/src/xenia/cpu/backend/x64/x64_sequences.cc +++ b/src/xenia/cpu/backend/x64/x64_sequences.cc @@ -2667,34 +2667,28 @@ EMITTER_OPCODE_TABLE(OPCODE_AND, AND_I8, AND_I16, AND_I32, AND_I64, AND_V128); 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. + // src1 constant. + // `and` instruction only supports up to 32-bit immediate constants + // 64-bit constants will need a temp register + if (i.dest.reg().getBit() == 64) { + auto temp = GetTempReg(e); + e.mov(temp, i.src1.constant()); - // `and` instruction only supports up to 32-bit immediate constants - // 64-bit constants will need a temp register - if (i.dest.reg().getBit() == 64) { - auto temp = GetTempReg(e); - e.mov(temp, i.src1.constant()); - - if (e.IsFeatureEnabled(kX64EmitBMI1)) { - if (i.dest.reg().getBit() == 64) { - e.andn(i.dest.reg().cvt64(), i.src2.reg().cvt64(), temp.cvt64()); - } else { - e.andn(i.dest.reg().cvt32(), i.src2.reg().cvt32(), temp.cvt32()); - } + if (e.IsFeatureEnabled(kX64EmitBMI1)) { + if (i.dest.reg().getBit() == 64) { + e.andn(i.dest.reg().cvt64(), i.src2.reg().cvt64(), temp.cvt64()); } else { - e.mov(i.dest, i.src2); - e.not_(i.dest); - e.and_(i.dest, temp); + e.andn(i.dest.reg().cvt32(), i.src2.reg().cvt32(), temp.cvt32()); } } else { e.mov(i.dest, i.src2); e.not_(i.dest); - e.and_(i.dest, uint32_t(i.src1.constant())); + e.and_(i.dest, temp); } + } else { + e.mov(i.dest, i.src2); + e.not_(i.dest); + e.and_(i.dest, uint32_t(i.src1.constant())); } } else if (i.src2.is_constant) { // src2 constant. diff --git a/src/xenia/cpu/compiler/passes/constant_propagation_pass.cc b/src/xenia/cpu/compiler/passes/constant_propagation_pass.cc index b6b0376fa..ffc8fe4a9 100644 --- a/src/xenia/cpu/compiler/passes/constant_propagation_pass.cc +++ b/src/xenia/cpu/compiler/passes/constant_propagation_pass.cc @@ -648,6 +648,14 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder, bool& result) { result = true; } break; + case OPCODE_AND_NOT: + if (i->src1.value->IsConstant() && i->src2.value->IsConstant()) { + v->set_from(i->src1.value); + v->AndNot(i->src2.value); + i->Remove(); + result = true; + } + break; case OPCODE_OR: if (i->src1.value->IsConstant() && i->src2.value->IsConstant()) { v->set_from(i->src1.value); diff --git a/src/xenia/cpu/hir/value.cc b/src/xenia/cpu/hir/value.cc index 28ed07ee7..a3d1a59b6 100644 --- a/src/xenia/cpu/hir/value.cc +++ b/src/xenia/cpu/hir/value.cc @@ -750,6 +750,13 @@ void Value::Not() { } } +void Value::AndNot(Value* other) { + assert_true(type == other->type); + Value second = Value(*other); + second.Not(); + And(&second); +} + void Value::Shl(Value* other) { assert_true(other->type == INT8_TYPE); switch (type) { diff --git a/src/xenia/cpu/hir/value.h b/src/xenia/cpu/hir/value.h index dcc95ca8c..96c71d561 100644 --- a/src/xenia/cpu/hir/value.h +++ b/src/xenia/cpu/hir/value.h @@ -516,6 +516,7 @@ class Value { void Or(Value* other); void Xor(Value* other); void Not(); + void AndNot(Value* other); void Shl(Value* other); void Shr(Value* other); void Sha(Value* other);