diff --git a/src/xenia/cpu/compiler/passes/constant_propagation_pass.cc b/src/xenia/cpu/compiler/passes/constant_propagation_pass.cc index b6b0376fa..acd1b5d64 100644 --- a/src/xenia/cpu/compiler/passes/constant_propagation_pass.cc +++ b/src/xenia/cpu/compiler/passes/constant_propagation_pass.cc @@ -712,7 +712,14 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder, bool& result) { result = true; } break; - // TODO(benvanik): ROTATE_LEFT + case OPCODE_ROTATE_LEFT: + if (i->src1.value->IsConstant() && i->src2.value->IsConstant()) { + v->set_from(i->src1.value); + v->RotateLeft(i->src2.value); + i->Remove(); + result = true; + } + break; case OPCODE_BYTE_SWAP: if (i->src1.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 666648b03..eb487325e 100644 --- a/src/xenia/cpu/hir/value.cc +++ b/src/xenia/cpu/hir/value.cc @@ -843,6 +843,29 @@ void Value::Sha(Value* other) { } } +void Value::RotateLeft(Value* other) { + assert_true(other->type == INT8_TYPE); + auto rotation = other->constant.u8; + + switch (type) { + case INT8_TYPE: + constant.u8 = rotate_left(constant.u8, rotation); + break; + case INT16_TYPE: + constant.u16 = rotate_left(constant.u16, rotation); + break; + case INT32_TYPE: + constant.u32 = rotate_left(constant.u32, rotation); + break; + case INT64_TYPE: + constant.u64 = rotate_left(constant.u64, rotation); + break; + default: + assert_unhandled_case(type); + break; + } +} + void Value::Extract(Value* vec, Value* index) { assert_true(vec->type == VEC128_TYPE); switch (type) { diff --git a/src/xenia/cpu/hir/value.h b/src/xenia/cpu/hir/value.h index dcc95ca8c..d2e0fbf6d 100644 --- a/src/xenia/cpu/hir/value.h +++ b/src/xenia/cpu/hir/value.h @@ -519,6 +519,7 @@ class Value { void Shl(Value* other); void Shr(Value* other); void Sha(Value* other); + void RotateLeft(Value* other); void Extract(Value* vec, Value* index); void Select(Value* other, Value* ctrl); void Splat(Value* other);