diff --git a/src/xenia/cpu/compiler/passes/constant_propagation_pass.cc b/src/xenia/cpu/compiler/passes/constant_propagation_pass.cc index b9dc393c7..b8690f48d 100644 --- a/src/xenia/cpu/compiler/passes/constant_propagation_pass.cc +++ b/src/xenia/cpu/compiler/passes/constant_propagation_pass.cc @@ -354,6 +354,13 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { i->Remove(); } break; + case OPCODE_MUL_HI: + if (i->src1.value->IsConstant() && i->src2.value->IsConstant()) { + v->set_from(i->src1.value); + v->MulHi(i->src2.value, (i->flags & ARITHMETIC_UNSIGNED) != 0); + i->Remove(); + } + break; case OPCODE_DIV: 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 c08f2b196..89e3a2f4a 100644 --- a/src/xenia/cpu/hir/value.cc +++ b/src/xenia/cpu/hir/value.cc @@ -304,6 +304,29 @@ void Value::Mul(Value* other) { } } +void Value::MulHi(Value* other, bool is_unsigned) { + assert_true(type == other->type); + switch (type) { + case INT32_TYPE: + if (is_unsigned) { + constant.i32 = (int32_t)(((uint64_t)((uint32_t)constant.i32) * (uint32_t)other->constant.i32) >> 32); + } else { + constant.i32 = (int32_t)(((int64_t)constant.i32 * (int64_t)other->constant.i32) >> 32); + } + break; + case INT64_TYPE: + if (is_unsigned) { + constant.i64 = __umulh(constant.i64, other->constant.i64); + } else { + constant.i64 = __mulh(constant.i64, other->constant.i64); + } + break; + default: + assert_unhandled_case(type); + break; + } +} + void Value::Div(Value* other, bool is_unsigned) { assert_true(type == other->type); switch (type) { diff --git a/src/xenia/cpu/hir/value.h b/src/xenia/cpu/hir/value.h index 0fc4cfcf6..ea0db6d01 100644 --- a/src/xenia/cpu/hir/value.h +++ b/src/xenia/cpu/hir/value.h @@ -385,6 +385,7 @@ class Value { bool Add(Value* other); bool Sub(Value* other); void Mul(Value* other); + void MulHi(Value* other, bool is_unsigned); void Div(Value* other, bool is_unsigned); static void MulAdd(Value* dest, Value* value1, Value* value2, Value* value3); static void MulSub(Value* dest, Value* value1, Value* value2, Value* value3);